Transforming Code into Beautiful, Idiomatic Python
本文内容可以在这里下载 http://tech.gladuo.com/beautiful_idiomatic_python.htmlNotes from Raymond Hettinger's talk at pycon US 2013 video, slides.The code examples and direct quotes are all from Raymond's talk. I've reproduced them here for my own edification and the hopes that others will find them as handy as I have!Looping over a range of numbersfor i in [0, 1, 2, 3, 4, 5]: print i**2 for i in range(6): print i**2Betterfor i in xrange(6): print i**2xrange creates an iterator over the range producing the values one at a time. This approach is much more memory efficient than range. xrange was renamed to range in python 3.Looping over a collectioncolors = ['red', 'green', 'blue', 'yellow'] for i in range(len(colors)): print colors[i]Betterfor color in colors: print colorLooping backwardscolors = ['red', 'green', 'blue', 'yellow'] for i in range(len(colors)-1, -1, -1): print colors[i]Betterfor color in reversed(colors): print colorLooping over a collection and indicescolors = ['red', 'green', 'blue', 'yellow'] for i in range(len(colors)): print i, '--->', colors[i]Betterfor i, color in enumerate(colors): print i, '--->', colorIt's fast and beautiful and saves you from tracking the individual indices and incrementing them.Whenever you find yourself manipulating indices [in a collection], you're probably doing it wrong.Looping over two collectionsnames = ['raymond', 'rachel', 'matthew'] colors = ['red', 'green', 'blue', 'yellow'] n = min(len(names), len(colors)) for i in range(n): print names[i], '--->', colors[i] for name, color in zip(names, colors): print name, '--->', colorBetterfor name, color in izip(names, colors): print name, '--->', colorzip creates a new list in memory and takes more memory. izip is more efficient than zip.Note: in python 3 izip was renamed to zip and promoted to a builtin replacing the old zip.Looping in sorted ordercolors = ['red', 'green', 'blue', 'yellow'] # Forward sorted order for color in sorted(colors): print colors # Backwards sorted order for color in sorted(colors, reverse=True): print colorsCustom Sort Ordercolors = ['red', 'green', 'blue', 'yellow'] def compare_length(c1, c2): if len(c1) < len(c2): return -1 if len(c1) > len(c2): return 1 return 0 print sorted(colors, cmp=compare_length)Betterprint sorted(colors, key=len)The original is slow and unpleasant to write. Also, comparison functions are no longer available in python 3.Call a function until a sentinel valueblocks = [] while True: block = f.read(32) if block == '': break blocks.append(block)Betterblocks = [] for block in iter(partial(f.read, 32), ''): blocks.append(block)iter takes two arguments. The first you call over and over again and the second is a sentinel value.Distinguishing multiple exit points in loopsdef find(seq, target): found = False for i, value in enumerate(seq): if value == target: found = True break if not found: return -1 return iBetterdef find(seq, target): for i, value in enumerate(seq): if value == target: break else: return -1 return iInside of every for loop is an else.Looping over dictionary keysd = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'} for k in d: print k for k in d.keys(): if k.startswith('r'): del d[k]When should you use the second and not the first? When you're mutating the dictionary.If you mutate something while you're iterating over it, you're living in a state of sin and deserve what ever happens to you.d.keys() makes a copy of all the keys and stores them in a list. Then you can modify the dictionary.Note: in python 3 to iterate through a dictionary you have to explicidly write: list(d.keys()) because d.keys() returns a "dictionary view" (an iterable that provide a dynamic view on the dictionary’s keys). See documentation.Looping over dictionary keys and values# Not very fast, has to re-hash every key and do a lookup for k in d: print k, '--->', d[k] # Makes a big huge list for k, v in d.items(): print k, '--->', vBetterfor k, v in d.iteritems(): print k, '--->', viteritems() is better as it returns an iterator.Note: in python 3 there is no iteritems() and items() behaviour is close to what iteritems() had. See documentation.Construct a dictionary from pairsnames = ['raymond', 'rachel', 'matthew'] colors = ['red', 'green', 'blue'] d = dict(izip(names, colors)) # {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}For python 3: d = dict(zip(names, colors))Counting with dictionariescolors = ['red', 'green', 'red', 'blue', 'green', 'red'] # Simple, basic way to count. A good start for beginners. d = {} for color in colors: if color not in d: d[color] = 0 d[color] += 1 # {'blue': 1, 'green': 2, 'red': 3}Betterd = {} for color in colors: d[color] = d.get(color, 0) + 1 # Slightly more modern but has several caveats, better for advanced users # who understand the intricacies d = defaultdict(int) for color in colors: d[color] += 1Grouping with dictionaries -- Part I and IInames = ['raymond', 'rachel', 'matthew', 'roger', 'betty', 'melissa', 'judith', 'charlie'] # In this example, we're grouping by name length d = {} for name in names: key = len(name) if key not in d: d[key] = [] d[key].append(name) # {5: ['roger', 'betty'], 6: ['rachel', 'judith'], 7: ['raymond', 'matthew', 'melissa', 'charlie']} d = {} for name in names: key = len(name) d.setdefault(key, []).append(name)Betterd = defaultdict(list) for name in names: key = len(name) d[key].append(name)Is a dictionary popitem() atomic?d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'} while d: key, value = d.popitem() print key, '-->', valuepopitem is atomic so you don't have to put locks around it to use it in threads.Linking dictionariesdefaults = {'color': 'red', 'user': 'guest'} parser = argparse.ArgumentParser() parser.add_argument('-u', '--user') parser.add_argument('-c', '--color') namespace = parser.parse_args([]) command_line_args = {k:v for k, v in vars(namespace).items() if v} # The common approach below allows you to use defaults at first, then override them # with environment variables and then finally override them with command line arguments. # It copies data like crazy, unfortunately. d = defaults.copy() d.update(os.environ) d.update(command_line_args)Betterd = ChainMap(command_line_args, os.environ, defaults)ChainMap has been introduced into python 3. Fast and beautiful.Improving ClarityPositional arguments and indicies are niceKeywords and names are betterThe first way is convenient for the computerThe second corresponds to how human’s thinkClarify function calls with keyword argumentstwitter_search('@obama', False, 20, True)Bettertwitter_search('@obama', retweets=False, numtweets=20, popular=True)Is slightly (microseconds) slower but is worth it for the code clarity and developer time savings.Clarify multiple return values with named tuples# Old testmod return value doctest.testmod() # (0, 4) # Is this good or bad? You don't know because it's not clear.Better# New testmod return value, a namedTuple doctest.testmod() # TestResults(failed=0, attempted=4)A namedTuple is a subclass of tuple so they still work like a regular tuple, but are more friendly.To make a namedTuple:TestResults = namedTuple('TestResults', ['failed', 'attempted'])Unpacking sequencesp = 'Raymond', 'Hettinger', 0x30, 'python@example.com' # A common approach / habit from other languages fname = p[0] lname = p[1] age = p[2] email = p[3]Betterfname, lname, age, email = pThe second approach uses tuple unpacking and is faster and more readable.Updating multiple state variablesdef fibonacci(n): x = 0 y = 1 for i in range(n): print x t = y y = x + y x = tBetterdef fibonacci(n): x, y = 0, 1 for i in range(n): print x x, y = y, x + yProblems with first approachx and y are state, and state should be updated all at once or in between lines that state is mis-matched and a common source of issuesordering mattersit's too low levelThe second approach is more high-level, doesn't risk getting the order wrong and is fast.Simultaneous state updatestmp_x = x + dx * t tmp_y = y + dy * t tmp_dx = influence(m, x, y, dx, dy, partial='x') tmp_dy = influence(m, x, y, dx, dy, partial='y') x = tmp_x y = tmp_y dx = tmp_dx dy = tmp_dyBetterx, y, dx, dy = (x + dx * t, y + dy * t, influence(m, x, y, dx, dy, partial='x'), influence(m, x, y, dx, dy, partial='y'))EfficiencyAn optimization fundamental ruleDon’t cause data to move around unnecessarilyIt takes only a little care to avoid O(n**2) behavior instead of linear behaviorBasically, just don't move data around unecessarily.Concatenating stringsnames = ['raymond', 'rachel', 'matthew', 'roger', 'betty', 'melissa', 'judith', 'charlie'] s = names[0] for name in names[1:]: s += ', ' + name print sBetterprint ', '.join(names)Updating sequencesnames = ['raymond', 'rachel', 'matthew', 'roger', 'betty', 'melissa', 'judith', 'charlie'] del names[0] # The below are signs you're using the wrong data structure names.pop(0) names.insert(0, 'mark')Betternames = deque(['raymond', 'rachel', 'matthew', 'roger', 'betty', 'melissa', 'judith', 'charlie']) # More efficient with deque del names[0] names.popleft() names.appendleft('mark')Decorators and Context ManagersHelps separate business logic from administrative logicClean, beautiful tools for factoring code and improving code reuseGood naming is essential.Remember the Spiderman rule: With great power, comes great responsibility!Using decorators to factor-out administrative logic# Mixes business / administrative logic and is not reusable def web_lookup(url, saved={}): if url in saved: return saved[url] page = urllib.urlopen(url).read() saved[url] = page return pageBetter@cache def web_lookup(url): return urllib.urlopen(url).read()Note: since python 3.2 there is a decorator for this in the standard library: functools.lru_cache.Factor-out temporary contexts# Saving the old, restoring the new old_context = getcontext().copy() getcontext().prec = 50 print Decimal(355) / Decimal(113) setcontext(old_context)Betterwith localcontext(Context(prec=50)): print Decimal(355) / Decimal(113)How to open and close filesf = open('data.txt') try: data = f.read() finally: f.close()Betterwith open('data.txt') as f: data = f.read()How to use locks# Make a lock lock = threading.Lock() # Old-way to use a lock lock.acquire() try: print 'Critical section 1' print 'Critical section 2' finally: lock.release()Better# New-way to use a lock with lock: print 'Critical section 1' print 'Critical section 2'Factor-out temporary contextstry: os.remove('somefile.tmp') except OSError: passBetterwith ignored(OSError): os.remove('somefile.tmp')ignored is is new in python 3.4, documentation.Note: ignored is actually called suppress in the standard library.To make your own ignored context manager in the meantime:@contextmanager def ignored(*exceptions): try: yield except exceptions: passStick that in your utils directory and you too can ignore exceptionsFactor-out temporary contexts# Temporarily redirect standard out to a file and then return it to normal with open('help.txt', 'w') as f: oldstdout = sys.stdout sys.stdout = f try: help(pow) finally: sys.stdout = oldstdoutBetterwith open('help.txt', 'w') as f: with redirect_stdout(f): help(pow)redirect_stdout is proposed for python 3.4, bug report.To roll your own redirect_stdout context manager@contextmanager def redirect_stdout(fileobj): oldstdout = sys.stdout sys.stdout = fileobj try: yield fieldobj finally: sys.stdout = oldstdoutConcise Expressive One-LinersTwo conflicting rules:Don’t put too much on one lineDon’t break atoms of thought into subatomic particlesRaymond’s rule:One logical line of code equals one sentence in EnglishList Comprehensions and Generator Expressionsresult = [] for i in range(10): s = i ** 2 result.append(s) print sum(result)Betterprint sum(i**2 for i in xrange(10))First way tells you what to do, second way tells you what you want.
Workflow for DjangoGithubadd / create / clone repoadd / commitsyncrevert虚拟环境mkvirtualenv project_namermvirtualenv project_namesetvirtualenvproject project_name PATHworkon project_namedeactiveStart Projectdjango-admin.py startproject project_namepython manage.py migratepython manage.py runserverStart App1. Start Apppython manage.py startapp app_name2. 修改 settings.py在project_name的settings.py文件中，找到INSTALLED_APPS列表，在列表的最后面增加 app_nameINSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app_name', ]3. 创建视图在app_name目录内的views.py文件中，删除注释# Create your views here.，创建视图def index(request): context_dict = {'boldmessage': "I am bold font from the context"} return render(request, 'rango/index.html', context_dict)4. 应用 URL 映射在app_name目录中，创建一个叫做urls.py的文件。from django.conf.urls import patterns, url from rango import views urlpatterns = [ url(r'^$', views.index, name='index')]5. 项目 URL 映射在project_name/project_name/urls.py中，更新urlpatterns列表。urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^app_name/', include('app_name.urls')) # for example ]使用模板1. 创建目录在project_name/创建一个templates目录，在这个目录中为每一个 app 建立一个目录，例如 project_name/templates/app_name，用来存放app_name应用下的模板2. 在 settings.py 中设置在setting.py中创建TEMPLATE_PATH变量，用它来储存 templates 目录。这里我们使用os.path.join()函数。TEMPLATE_PATH = os.path.join(BASE_DIR, 'templates')TEMPLATE_DIRS = [ # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. TEMPLATE_PATH, ]3. 添加模板在template/app_name/目录里建立一个叫做index.html的文件,在新文件里加入下面代码： App App says... hello world! {{ boldmessage }} About 4. 在 views.py 中 renderfrom django.shortcuts import render def index(request): # Construct a dictionary to pass to the template engine as its context. # Note the key boldmessage is the same as {{ boldmessage }} in the template! context_dict = {'boldmessage': "I am bold font from the context"} # Return a rendered response to send to the client. # We make use of the shortcut function to make our lives easier. # Note that the first parameter is the template we wish to use. return render(request, 'rango/index.html', context_dict)使用静态资源1. 设置静态目录在settings.py文件,我们需要更新两个变量STATIC_URL和STATICFILES_DIRS元组，像下面一样创建一个储存静态目录(STATIC_PATH)的变量。STATIC_PATH = os.path.join(BASE_DIR,'static') STATIC_URL = '/static/' # You may find this is already defined as such. STATICFILES_DIRS = [ STATIC_PATH, ]2. 使用静态资源 {% load static %} Rango App says... hello world! {{ boldmessage }} About 创建模型1. 数据库设置在settings.py里添加一个叫做DATABASES的字典DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } }2. 模型创建class Category(models.Model): name = models.CharField(max_length=128, unique=True) def __unicode__(self): #For Python 2, use __str__ on Python 3 return self.name class Page(models.Model): category = models.ForeignKey(Category) title = models.CharField(max_length=128) url = models.URLField() views = models.IntegerField(default=0) def __unicode__(self): #For Python 2, use __str__ on Python 3 return self.title2. 设置管理界面打开rango/admin.py输入如下代码：from django.contrib import admin from rango.models import Category, Page admin.site.register(Category) admin.site.register(Page)3. 数据模型迁移makemigrations app_name$ python manage.py makemigrations rango Migrations for 'rango': 0001_initial.py: - Create model Category - Create model Pagemigrate$ python manage.py migrate Operations to perform: Apply all migrations: admin, rango, contenttypes, auth, sessions Running migrations: Applying rango.0001_initial... OKMTV在Django中创建数据驱动页面必须执行以下5步。首先，在你应用的views.py文件中导入你要添加的模型。在视图里访问模型，导入你需要的数据。把模型的数据传递给模板。设置模板给用户呈现数据。如果还没有映射URL，映射一下吧。
编码的历史ASCIIASCII(American Standard Code forInformation Interchange)，是一种单字节的编码。计算机世界里一开始只有英文，而单字节可以表示256个不同的字符，可以表示所有的英文字符和许多的控制符号。不过ASCII只用到了其中的一半（\x80以下），这也是MBCS得以实现的基础。MBCS然而计算机世界里很快就有了其他语言，单字节的ASCII已无法满足需求。后来每个语言就制定了一套自己的编码，由于单字节能表示的字符太少，而且同时也需要与ASCII编码保持兼容，所以这些编码纷纷使用了多字节来表示字符，如GBxxx、BIGxxx等等，他们的规则是，如果第一个字节是\x80以下，则仍然表示ASCII字符；而如果是\x80以上，则跟下一个字节一起（共两个字节）表示一个字符，然后跳过下一个字节，继续往下判断。这里，IBM发明了一个叫Code Page的概念，将这些编码都收入囊中并分配页码，GBK是第932页，也就是CP932。所以，也可以使用CP932表示GBK。MBCS(Multi-Byte Character Set)是这些编码的统称。目前为止大家都是用了双字节，所以有时候也叫做DBCS(Double-Byte Character Set)。必须明确的是，MBCS并不是某一种特定的编码，Windows里根据你设定的区域不同，MBCS指代不同的编码，而Linux里无法使用MBCS作为编码。在Windows中你看不到MBCS这几个字符，因为微软为了更加洋气，使用了ANSI来吓唬人，记事本的另存为对话框里编码ANSI就是MBCS。同时，在简体中文Windows默认的区域设定里，指代GBK。Unicode后来，有人开始觉得太多编码导致世界变得过于复杂了，让人脑袋疼，于是大家坐在一起拍脑袋想出来一个方法：所有语言的字符都用同一种字符集来表示，这就是Unicode。最初的Unicode标准UCS-2使用两个字节表示一个字符，所以你常常可以听到Unicode使用两个字节表示一个字符的说法。但过了不久有人觉得256*256太少了，还是不够用，于是出现了UCS-4标准，它使用4个字节表示一个字符，不过我们用的最多的仍然是UCS-2。UCS(Unicode Character Set)还仅仅是字符对应码位的一张表而已，比如"汉"这个字的码位是6C49。字符具体如何传输和储存则是由UTF(UCS Transformation Format)来负责。一开始这事很简单，直接使用UCS的码位来保存，这就是UTF-16，比如，"汉"直接使用\x6C\x49保存(UTF-16-BE)，或是倒过来使用\x49\x6C保存(UTF-16-LE)。但用着用着美国人觉得自己吃了大亏，以前英文字母只需要一个字节就能保存了，现在大锅饭一吃变成了两个字节，空间消耗大了一倍……于是UTF-8横空出世。UTF-8是一种很别扭的编码，具体表现在他是变长的，并且兼容ASCII，ASCII字符使用1字节表示。然而这里省了的必定是从别的地方抠出来的，你肯定也听说过UTF-8里中文字符使用3个字节来保存吧？4个字节保存的字符更是在泪奔……（具体UCS-2是怎么变成UTF-8的请自行搜索）另外值得一提的是BOM(Byte Order Mark)。我们在储存文件时，文件使用的编码并没有保存，打开时则需要我们记住原先保存时使用的编码并使用这个编码打开，这样一来就产生了许多麻烦。（你可能想说记事本打开文件时并没有让选编码？不妨先打开记事本再使用文件-> 打开看看）而UTF则引入了BOM来表示自身编码，如果一开始读入的几个字节是其中之一，则代表接下来要读取的文字使用的编码是相应的编码：BOM_UTF8 '\xef\xbb\xbf' BOM_UTF16_LE '\xff\xfe' BOM_UTF16_BE '\xfe\xff' 并不是所有的编辑器都会写入BOM，但即使没有BOM，Unicode还是可以读取的，只是像MBCS的编码一样，需要另行指定具体的编码，否则解码将会失败。你可能听说过UTF-8不需要BOM，这种说法是不对的，只是绝大多数编辑器在没有BOM时都是以UTF-8作为默认编码读取。即使是保存时默认使用ANSI(MBCS)的记事本，在读取文件时也是先使用UTF-8测试编码，如果可以成功解码，则使用UTF-8解码。记事本这个别扭的做法造成了一个BUG：如果你新建文本文件并输入"姹塧"然后使用ANSI(MBCS)保存，再打开就会变成"汉a"，你不妨试试python中的编码python中的str和unicodepython中的str和unicodepython中的字符串有两种：str和unicode。str和unicode都是basestring的子类。严格意义上说，str其实是字节串，它是unicode经过编码后的字节组成的序列。它们都有两个方法：encode和decode：encode是指将unicode转换成其他格式的编码decode是指将其他格式的编码转换成unicodedecode和encode示例代码：#coding=utf-8 u1 = u’你好’ print repr(u1) s = u1.encode(‘utf-8’) print repr(s) u2 = s.decode(‘utf-8’) print repr(u2)输出：u'\u4f60\u597d' '\xe4\xbd\xa0\xe5\xa5\xbd' u'\u4f60\u597d'需要注意的是，对str调用encode()方法是错误的，虽然实际上Python不会抛出异常，而是返回另外一个相同内容但不同id的str；对 unicode调用decode()方法也是这样。再来看一下str和unicode长度的区别：#coding=utf-8 s1 = ‘你好’ s2 = u’你好’ print len(s1) print len(s2)输出 6和2这是因为，s1其实是经过unicode编码后的字节序列，而UTF-8对“你好”这两个字，每个字都用了三个字节来表示，因而导致它的长度为6。而s2是unicode，“你好”中的每一个字都对应一个unicode字符，所以长度为2。python字符编码声明不管是str还是unicode，字符串在python内部的表示都是unicode编码，它相当于一种统一的中间编码。所以经常会需要从其他编码成unicode，或者从unicode解码到其他编码。这就意味着，对于代码文件，或者其他内容，不管这些内容的编码是ASCII还是UTF-8，python都会把这些内容转换成它所接受的编码—即unicode。现在试着把下面代码写到文件中，enc.py：s1='你好' s2=u'你好' print repr(s1) print repr(s2)执行脚本：python enc.py，出错了：File "enc.py", line 1 yntaxError: Non-ASCII character '\xc4' infile enc.py on line 1, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details 这是因为python解析器读取代码文件本身时，会试图把它转成unicode。但是上面的代码文件中出现了中文，并且文件头上没有任何的编码声明，python就会试图采用默认的ASCII编码来把中文转成unicode，但是显然，ASCII无法将中文转成unicode，所以它报错了。我们在文件的第一行加上声明：#coding=utf-8（注：实际上Python只检查#、coding和编码字符串，其他的字符都是为了美观加上的。另外，Python中可用的字符编码有很多，并且还有许多别名，还不区分大小写，比如UTF-8可以写成u8。参见http://docs.python.org/library/codecs.html#standard-encodings）输出：'\xe4\xbd\xa0\xe5\xa5\xbd' u'\u4f60\u597d' 另外需要注意的是声明的编码必须与文件实际保存时用的编码一致，否则很大几率会出现代码解析异常。现在的IDE一般会自动处理这种情况，改变声明后同时换成声明的编码保存，但文本编辑器控们需要小心。OK，再改一下代码：#coding=utf-8 s1 = '你好' s2 = u'你好' print s1 print s2再执行一下，输出了：浣犲ソ 你好 这里第一个“你好”变成乱码了。这是因为，python解析器看到了UTF-8的编码声明，于是把s1转换从UTF-8转换成了unicode。而调用print的时候，它又试图将由UTF-8解码成unicode的字符串编码成gbk（下面解释为什么会转成gbk）的字符串，这时就出现乱码了。而s2本来就已经是unicode了，所以不会有影响。为什么print的时候要转成gbk呢，这里需要解释一下python中print的工作原理：print只是把字节串传递给操作系统，而由操作系统决定以何种编码输出。对于普通的ASCII字节串，当然是直接输出。而对于unicode，就依赖于stdout的输出编码了。控制台里默认的编码是gbk（可以通过查看cmd.exe窗口属性看到），所以它会试图把unicode编码成gbk。（注意不同的编辑器，如vim，IDLE，Eclipse使用的输出编码都是不一致的。所以，在一个地方能正常输出中文，不代码在所有地方都能正常地输出中文）这里我们再改一下，直接把下面的代码在python的交互式shell中执行：s1 = '你好' s2 = u'你好' print s1 print s2为什么这时又都正确地输出了中文呢？因为现在是在控制台，默认编码就是gbk。所以对于s1，它会从gbk解码到unicode。输出时再编码回gbk，这时就能正常地输出了。python读写文件内置的open()方法打开文件时，read()读取的是str，读取后需要使用正确的编码格式进行decode()。write()写入时，如果参数是 unicode，则需要使用你希望写入的编码进行encode()，如果是其他编码格式的str，则需要先用该str的编码进行decode()，转成 unicode后再使用写入的编码进行encode()。如果直接将unicode作为参数传入write()方法，Python将先使用源代码文件声明的字符编码进行编码然后写入。#coding=utf-8 f = open(‘in.txt’) line = f.read() f.close() print type(line) #输出type ‘str’ u1 = line.decode(‘gbk’) f = open(‘out.txt’, ‘w’) line2 = u1.encode(‘utf-8’) f.write(line2) f.close()另外，模块codecs提供了一个open()方法，可以指定一个编码打开文件，使用这个方法打开的文件读取返回的将是unicode。写入时，如果参数是unicode，则使用open()时指定的编码进行编码后写入；如果是str，则先根据源代码文件声明的字符编码，解码成unicode后再进行前述操作。相对内置的open()来说，这个方法比较不容易在编码上出现问题。数据库中使用中文a. 设置mysql中的charset是UTF-8的，然后在python代码文件中设置#coding=utf-8。b. 使用MySQLdb连接数据库时，要加上charset='utf-8'的选项，不然它会以默认的编码去读取数据库的内容。确保了1和2之后，就能正常地读取中文数据了。json读写的中文读：json.loads(f, encoding="utf-8")写：json.dumps(f, ensure_ascii=False,indent=2) #indent=2 按更visualable的方式显示 参考链接：1. http://blog.csdn.net/inte_sleeper/article/details/6676351
在看的时候，在引入blueprint之后看到了类似from ...foo import bar这样的代码段，这种导入包的方式前所未见，甚至让我产生了这是一个blueprint的封装过的导入方式的错觉，但是总觉得哪哪都不对劲。翻遍了整个书，没有看到对这种“新花样”的解释——甚至专门买来中文版，来看看我有没有什么漏掉的东西，结果一无所获。然后便以Flask import 类似的词语Google还是没有什么结果，期间读到了一份很好的python网页教程，最终终于意识到python知识还很缺乏，这应该是某种导入包的“新”的黑魔法。断断续续在一些blog上看到了关于相对路径导入的信息，在PEP8这个页面看到了推荐使用绝对路径，而相对路径是可接受的，理由是Absolute imports are recommended, as they are usually more readable and tend to be better behaved这理由我就简洁的不能信服了，虽然是python官方的说法。晚上回来调DEV-CPP还是不乖，大概是这辈子遇到的最心塞的事了，就像喜欢一个妹子，不断满足她的下限，到现在已经到了再也不能下的下限了，她还不满意，此时我只想说，你TMD赶紧听话，不然我哭给你看。。。打开python页面搜索relative imports最终还是搜到了想要的内容，Guido's DecisionGuido has Pronounced [1] that relative imports will use leading dots. A single leading dot indicates a relative import,starting with the current package. Two or more leading dots give arelative import to the parent(s) of the current package, one level perdot after the first. Here's a sample package layout: package/ __init__.py subpackage1/ __init__.py moduleX.py moduleY.py subpackage2/ __init__.py moduleZ.py moduleA.py Assuming that the current file is either moduleX.py or subpackage1/__init__.py , following are correct usages of the newsyntax:from .moduleY import spam from .moduleY import spam as ham from .import moduleY from ..subpackage1 import moduleY from..subpackage2.moduleZ import eggs from ..moduleA import foo from...package import bar from ...sys import path Note that while thatlast case is legal, it is certainly discouraged ("insane" was the wordGuido used).Relative imports must always use from <> import ; import <> is alwaysabsolute. Of course, absolute imports can use from <> import byomitting the leading dots. The reason import .foo is prohibited isbecause afterimport XXX.YYY.ZZZ thenXXX.YYY.ZZZ is usable in an expression. But.moduleY is not usable in an expression.很清楚了，一个点代表同级目录，多一个点往上一级，上到最高就等于整个PATH环境了。而且，relative import 只支持 from <> import <> 这种结构。Gudio's decision，很吊的样子，想起来了I write python的梗。喜欢有一点点约束的最佳实践。人生苦短，我用python，晚安。