Hidden features of Python
什么是Python编程语言中鲜为人知但有用的特性?
- 尝试限制对python核心的答案。
- 每个答案一个功能。
- 给出该特性的一个示例和简短描述,而不仅仅是指向文档的链接。
- 使用标题作为第一行标记功能。
快速链接到答案:
- 参数解包
- 支撑
- 链接比较运算符
- 装饰者
- 默认参数gotchas/可变默认参数的危险
- 描述符
- 字典默认
.get 值 - 文档串测试
- 省略号切片语法
- 枚举
- 为/其他
- 函数作为iter()参数
- 生成器表达式
import this - 就地值交换
- 列表步进
__missing__ 项- 多行正则表达式
- 命名字符串格式
- 嵌套列表/生成器理解
- 运行时的新类型
.pth 文件- ROT13编码
- 正则表达式调试
- 发送到发电机
- 交互式解释器中的制表符完成
- 三元表达式
try/except/else - 解包+
print() 功能 with 报表
链接比较运算符:
1 2 3 4 5 6 7 8 9 10 11 | >>> x = 5 >>> 1 < x < 10 True >>> 10 < x < 20 False >>> x < 10 < x*10 < 100 True >>> 10 > x <= 9 True >>> 5 == x > 4 True |
如果你认为这是在做
获取python regex解析树以调试regex。
正则表达式是Python的一个很好的特性,但是调试它们可能很麻烦,而且很容易出错。
幸运的是,python可以通过将未记录的、实验性的、隐藏的标志
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | >>> re.compile("^\[font(?:=(?P<size>[-+][0-9]{1,2}))?\](.*?)[/font]", re.DEBUG) at at_beginning literal 91 literal 102 literal 111 literal 110 literal 116 max_repeat 0 1 subpattern None literal 61 subpattern 1 in literal 45 literal 43 max_repeat 1 2 in range (48, 57) literal 93 subpattern 2 min_repeat 0 65535 any None in literal 47 literal 102 literal 111 literal 110 literal 116 |
一旦理解了语法,就可以发现错误。在那里,我们可以看到我忘记了在
当然,您可以将它与您想要的任何标志结合起来,例如注释的regex:
1 2 3 4 5 6 7 8 9 10 | >>> re.compile(""" ^ # start of a line \[font # the font tag (?:=(?P<size> # optional [font=+size] [-+][0-9]{1,2} # size specification ))? \] # end of tag (.*?) # text between the tags \[/font\] # end of the tag """, re.DEBUG|re.VERBOSE|re.DOTALL) |
使用enumerate
在一个使用enumerate包可迭代变量和它想随着ITS项目收益的指标。
例如:
1 2 3 4 5 6 7 8 9 | >>> a = ['a', 'b', 'c', 'd', 'e'] >>> for index, item in enumerate(a): print index, item ... 0 a 1 b 2 c 3 d 4 e >>> |
参考文献:
- Python教程循环技术
- Python文档的
enumerate 内置函数 - PEP 279
创建生成器对象
如果你写
1 | x=(n for n in foo if bar(n)) |
你可以拿出发电机,把它分配给X。现在它意味着你可以
1 | for n in x: |
这样做的好处是,您不需要中间存储,如果需要的话,就需要中间存储。
1 | x = [n for n in foo if bar(n)] |
在某些情况下,这会导致显著的加速。
您可以将许多if语句附加到生成器的末尾,基本上复制嵌套for循环:
1 2 3 4 5 6 7 8 | >>> n = ((a,b) for a in range(0,2) for b in range(4,6)) >>> for i in n: ... print i (0, 4) (0, 5) (1, 4) (1, 5) |
iter()不能接受可调用参数
例如:
1 2 3 4 | def seek_next_line(f): for c in iter(lambda: f.read(1),' '): pass |
注意可变的默认参数
1 2 3 4 5 6 7 8 9 10 | >>> def foo(x=[]): ... x.append(1) ... print x ... >>> foo() [1] >>> foo() [1, 1] >>> foo() [1, 1, 1] |
相反,您应该使用表示"未给定"的sentinel值,并将其替换为默认的可变值:
1 2 3 4 5 6 7 8 9 | >>> def foo(x=None): ... if x is None: ... x = [] ... x.append(1) ... print x >>> foo() [1] >>> foo() [1] |
向生成器函数发送值。例如,具有此功能:
1 2 3 4 5 6 7 | def mygen(): """Yield 5 until something else is passed back via send()""" a = 5 while True: f = (yield a) #yield a and possibly get f in return if f is not None: a = f #store the new value |
你可以:
1 2 3 4 5 6 7 8 9 | >>> g = mygen() >>> g.next() 5 >>> g.next() 5 >>> g.send(7) #we send this back to the generator 7 >>> g.next() #now it will yield 7 until we send something else 7 |
如果您不喜欢使用空格来表示范围,可以使用C样式,方法是发出:
1 | from __future__ import braces |
slice运算符中的step参数。例如:
1 2 3 | a = [1,2,3,4,5] >>> a[::2] # iterate over the whole list in 2-increments [1,3,5] |
特例
1 2 | >>> a[::-1] [5,4,3,2,1] |
装饰者
修饰符允许将一个函数或方法包装在另一个函数中,该函数或方法可以添加功能、修改参数或结果等。您可以在函数定义的上方一行编写修饰符,从"at"符号(@)开始。
示例显示了一个
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> def print_args(function): >>> def wrapper(*args, **kwargs): >>> print 'Arguments:', args, kwargs >>> return function(*args, **kwargs) >>> return wrapper >>> @print_args >>> def write(text): >>> print text >>> write('foo') Arguments: ('foo',) {} foo |
在else for语法(http://docs.python.org湖/编号/ for.html)
1 2 3 4 5 | for i in foo: if i == 0: break else: print("i was never 0") |
"else"块都将执行最后的一环,除非是被打破。
上面的代码可以被仿真为如下:
1 2 3 4 5 6 7 | found = False for i in foo: if i == 0: found = True break if not found: print("i was never 0") |
从2.5开始,dicts有一个特殊的方法
1 2 3 4 5 6 7 8 9 10 | >>> class MyDict(dict): ... def __missing__(self, key): ... self[key] = rv = [] ... return rv ... >>> m = MyDict() >>> m["foo"].append(1) >>> m["foo"].append(2) >>> dict(m) {'foo': [1, 2]} |
在
1 2 3 4 5 6 | >>> from collections import defaultdict >>> m = defaultdict(list) >>> m["foo"].append(1) >>> m["foo"].append(2) >>> dict(m) {'foo': [1, 2]} |
我建议在将此类dict传递给不需要此类子类的函数之前,先将其转换为常规dict。许多代码使用
就地值交换
1 2 3 4 5 6 7 8 | >>> a = 10 >>> b = 5 >>> a, b (10, 5) >>> a, b = b, a >>> a, b (5, 10) |
赋值的右侧是一个创建新元组的表达式。任务的左侧立即将(未引用的)元组解包到名称
赋值后,新的元组未被引用并标记为垃圾收集,绑定到
如数据结构的python教程部分所述,
Note that multiple assignment is really just a combination of tuple packing and sequence unpacking.
可读的正则表达式
在Python中,可以将正则表达式拆分为多行,命名匹配项并插入注释。
示例详细语法(从深入到python):
1 2 3 4 5 6 7 8 9 10 11 12 | >>> pattern =""" ... ^ # beginning of string ... M{0,4} # thousands - 0 to 4 M's ... (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's), ... # or 500-800 (D, followed by 0 to 3 C's) ... (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's), ... # or 50-80 (L, followed by 0 to 3 X's) ... (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's), ... # or 5-8 (V, followed by 0 to 3 I's) ... $ # end of string ...""" >>> re.search(pattern, 'M', re.VERBOSE) |
示例命名匹配(来自正则表达式howto)
1 2 3 4 | >>> p = re.compile(r'(?P<word>\b\w+\b)') >>> m = p.search( '(((( Lots of punctuation )))' ) >>> m.group('word') 'Lots' |
由于字符串文字串联,您还可以在不使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> pattern = ( ... "^" # beginning of string ... "M{0,4}" # thousands - 0 to 4 M's ... "(CM|CD|D?C{0,3})" # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's), ... # or 500-800 (D, followed by 0 to 3 C's) ... "(XC|XL|L?X{0,3})" # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's), ... # or 50-80 (L, followed by 0 to 3 X's) ... "(IX|IV|V?I{0,3})" # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's), ... # or 5-8 (V, followed by 0 to 3 I's) ... "$" # end of string ... ) >>> print pattern "^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$" |
函数参数解箱
可以使用
例如:
1 2 3 4 5 6 7 8 | def draw_point(x, y): # do some magic point_foo = (3, 4) point_bar = {'y': 3, 'x': 2} draw_point(*point_foo) draw_point(**point_bar) |
非常有用的快捷方式,因为列表、元组和dict被广泛用作容器。
当您在代码文件顶部使用正确的编码声明时,rot13是源代码的有效编码:
1 2 3 4 | #!/usr/bin/env python # -*- coding: rot13 -*- cevag"Uryyb fgnpxbiresybj!".rapbqr("rot13") |
以完全动态的方式创建新类型
1 2 3 4 5 | >>> NewType = type("NewType", (object,), {"x":"hello <hr><P>上下文管理器和"<wyn>with</wyn>声明"</P><P>在PEP343中引入的上下文管理器是一个对象,用作一组语句的运行时上下文。</P><P>由于该特性使用了新的关键字,因此逐渐引入:它通过<wyn>__future__</wyn>指令在python 2.5中可用。默认情况下,python 2.6及更高版本(包括python 3)具有可用性。</P><P>我经常使用"with"语句,因为我认为它是一个非常有用的结构,下面是一个快速演示:</P>[cc lang="python"]from __future__ import with_statement with open('foo.txt', 'w') as f: f.write('hello!') |
在幕后发生的是,"with"语句调用文件对象上的特殊
在这种特殊情况下,这对您的作用是,它保证在执行超出
其他常见的用例包括使用线程和数据库事务进行锁定。
字典有get()方法
字典有一个"get()"方法。如果你做了d[‘key’]但key不在,你会得到一个例外。如果你做了d.get("key"),如果没有"key",你就什么也得不到。可以添加第二个参数以返回该项,而不是不返回任何项,例如:d.get("key",0)。
它非常适用于数字相加:
描述符
它们是一系列核心python特性背后的魔力。
当使用点式访问查找成员(例如x.y)时,python首先在实例字典中查找该成员。如果找不到,它会在类字典中查找。如果它在类字典中找到它,并且对象实现了描述符协议,而不是仅仅返回它,那么Python将执行它。描述符是实现
以下是使用描述符实现自己的(只读)属性版本的方法:
1 2 3 4 5 6 7 8 | class Property(object): def __init__(self, fget): self.fget = fget def __get__(self, obj, type): if obj is None: return self return self.fget(obj) |
您可以像使用内置属性()一样使用它:
1 2 3 4 | class MyClass(object): @Property def foo(self): return"Foo!" |
在Python中,描述符用于实现属性、绑定方法、静态方法、类方法和槽等等。理解它们很容易理解为什么以前看起来像Python"怪癖"的很多东西都是这样的。
RaymondHettinger有一个优秀的教程,它比我更好地描述它们。
条件分配
1 | x = 3 if (y == 1) else 2 |
它到底是什么样的声音:"如果y是3至指定的X 1,X 2,否则分配到"。注意,这是没有必要的,但我的父母,他们为readability样。所以你可以链它如果你有更多的东西):
1 | x = 3 if (y == 1) else 2 if (y == -1) else 1 |
虽然在某些点,它太远了一点。
注意你可以使用if…在任何其他的表达。例如:
1 | (func1 if y == 1 else func2)(arg1, arg2) |
我想如果是func1 1和y的函数,否则。在两个情况下相应的函数的参数要与arg1和arg2。
analogously,以下是有效的:
1 | x = (class1 if y == 1 else class2)(arg1, arg2) |
在Class1和Class2是两类。
doctest:同时进行文档和单元测试。
从python文档中提取的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | def factorial(n): """Return the factorial of n, an exact integer >= 0. If the result is small enough to fit in an int, return an int. Else return a long. >>> [factorial(n) for n in range(6)] [1, 1, 2, 6, 24, 120] >>> factorial(-1) Traceback (most recent call last): ... ValueError: n must be >= 0 Factorials of floats are OK, but the float must be an exact integer: """ import math if not n >= 0: raise ValueError("n must be >= 0") if math.floor(n) != n: raise ValueError("n must be exact integer") if n+1 == n: # catch a value like 1e300 raise OverflowError("n too large") result = 1 factor = 2 while factor <= n: result *= factor factor += 1 return result def _test(): import doctest doctest.testmod() if __name__ =="__main__": _test() |
命名格式
%-格式化需要字典(还应用%i/%s等验证)。
1 2 3 4 5 6 7 | >>> print"The %(foo)s is %(bar)i." % {'foo': 'answer', 'bar':42} The answer is 42. >>> foo, bar = 'question', 123 >>> print"The %(foo)s is %(bar)i." % locals() The question is 123. |
而且由于locals()也是一个字典,所以您可以简单地将其作为dict传递,并从本地变量中获得.%的子项。我认为这是不允许的,但可以简化事情。
新样式格式
1 | >>> print("The {foo} is {bar}".format(foo='answer', bar=42)) |
为了添加更多的python模块(尤其是第三方模块),大多数人似乎使用pythonpath环境变量,或者在他们的站点包目录中添加符号链接或目录。另一种方法是使用*.pth文件。下面是python文档的官方解释:
"The most convenient way [to modify
python's search path] is to add a path
configuration file to a directory
that's already on Python's path,
usually to the .../site-packages/
directory. Path configuration files
have an extension of .pth, and each
line must contain a single path that
will be appended to sys.path. (Because
the new paths are appended to
sys.path, modules in the added
directories will not override standard
modules. This means you can't use this
mechanism for installing fixed
versions of standard modules.)"
异常else子句:
1 2 3 4 5 6 7 8 | try: put_4000000000_volts_through_it(parrot) except Voom: print"'E's pining!" else: print"This parrot is no more!" finally: end_sketch() |
使用else子句比向try子句添加其他代码要好,因为它可以避免意外捕获一个没有被try保护的代码引发的异常…except语句。
请参阅http://docs.python.org/tut/node10.html
重新提出例外:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # Python 2 syntax try: some_operation() except SomeError, e: if is_fatal(e): raise handle_nonfatal(e) # Python 3 syntax try: some_operation() except SomeError as e: if is_fatal(e): raise handle_nonfatal(e) |
错误处理程序中没有参数的"raise"语句告诉python在原始跟踪完整的情况下重新引发异常,允许您说"哦,对不起,对不起,我不是有意捕获它,对不起,对不起。"
如果您希望打印、存储或篡改原始的回溯,可以使用sys.exc_info()获取它,并像python使用"回溯"模块一样打印它。
主要消息:)
1 2 | import this # btw look at this module's source :) |
解密码:
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
交互式解释器选项卡完成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | try: import readline except ImportError: print"Unable to load readline module." else: import rlcompleter readline.parse_and_bind("tab: complete") >>> class myclass: ... def function(self): ... print"my function" ... >>> class_instance = myclass() >>> class_instance.<TAB> class_instance.__class__ class_instance.__module__ class_instance.__doc__ class_instance.function >>> class_instance.f<TAB>unction() |
您还必须设置pythonstartup环境变量。
1 2 3 4 5 6 7 8 9 10 11 12 | >>> a = set([1,2,3,4]) >>> b = set([3,4,5,6]) >>> a | b # Union {1, 2, 3, 4, 5, 6} >>> a & b # Intersection {3, 4} >>> a < b # Subset False >>> a - b # Difference {1, 2} >>> a ^ b # Symmetric Difference {1, 2, 5, 6} |
标准库参考中的更多详细信息:集合类型
嵌套列表理解和生成器表达式:
1 2 | [(i,j) for i in range(3) for j in range(i) ] ((i,j) for i in range(4) for j in range(i) ) |
这些可以替换大量嵌套循环代码。
负轮
1 2 3 4 | >>> str(round(1234.5678, -2)) '1200.0' >>> str(round(1234.5678, 2)) '1234.57' |
注:
乘以布尔值
我在Web开发中经常做的一件事是有选择地打印HTML参数。我们在其他语言中都看到过这样的代码:
1 | class='<% isSelected ?"selected" :"" %>' |
在python中,您可以用一个布尔值相乘,它完全按照您期望的那样做:
1 | class='<%"selected" * isSelected %>' |
这是因为乘法将布尔值强制为整数(0表示假,1表示真),在python中,用一个字符串乘以一个int会重复n次字符串。
python的高级切片操作有一个鲜为人知的语法元素,即省略号:
1 2 3 4 5 6 | >>> class C(object): ... def __getitem__(self, item): ... return item ... >>> C()[1:2, ..., 3] (slice(1, 2, None), Ellipsis, 3) |
不幸的是,它几乎没有用处,因为只有涉及到元组时才支持省略号。
重新调用函数!
每次有东西匹配正则表达式时都可以调用函数,这一事实非常方便。这里我有一个例子,用"嗨"替换每个"你好",用"弗雷德"替换"那里",等等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import re def Main(haystack): # List of from replacements, can be a regex finds = ('Hello', 'there', 'Bob') replaces = ('Hi,', 'Fred,', 'how are you?') def ReplaceFunction(matchobj): for found, rep in zip(matchobj.groups(), replaces): if found != None: return rep # log error return matchobj.group(0) named_groups = [ '(%s)' % find for find in finds ] ret = re.sub('|'.join(named_groups), ReplaceFunction, haystack) print ret if __name__ == '__main__': str = 'Hello there Bob' Main(str) # Prints 'Hi, Fred, how are you?' |
在python 3中解包tuple
在Python3中,可以使用与函数定义中可选参数相同的语法来解包元组:
1 2 3 4 5 6 7 | >>> first,second,*rest = (1,2,3,4,5,6,7,8) >>> first 1 >>> second 2 >>> rest [3, 4, 5, 6, 7, 8] |
但是,一个不太知名、功能更强大的特性允许您在列表中间包含未知数量的元素:
1 2 3 4 5 6 7 | >>> first,*rest,last = (1,2,3,4,5,6,7,8) >>> first 1 >>> rest [2, 3, 4, 5, 6, 7] >>> last 8 |
多行字符串
一种方法是使用反斜杠:
1 2 3 4 | >>> sql ="select * from some_table \ where id > 10" >>> print sql select * from some_table where id > 10 |
另一种方法是使用三重引号:
1 2 3 4 | >>> sql ="""select * from some_table where id > 10""" >>> print sql select * from some_table where id > 10 |
问题在于它们没有缩进(代码中看起来很糟糕)。如果你试图缩进,它只会打印出你输入的空白。
我最近发现的第三个解决方案是将字符串分成行并用括号括起来:
1 2 3 4 5 | >>> sql = ("select * from some_table" # <-- no comma, whitespace at end "where id > 10" "order by name") >>> print sql select * from some_table where id > 10 order by name |
注意行与行之间没有逗号(这不是元组),并且必须考虑到字符串所需的任何尾随/前导空格。顺便说一下,所有这些都是与占位符一起工作的(比如
根据许多人的要求,这个答案已经被转移到问题本身。
- 它包含一个下划线,显示最新的输出值(由解释器在交互式会话):
1 2 3 4 5 | >>> (a for a in xrange(10000)) <generator object at 0x81a8fcc> >>> b = 'blah' >>> _ <generator object at 0x81a8fcc> |
- 控制器:一个方便的Web浏览器
1 2 | >>> import webbrowser >>> webbrowser.open_new_tab('http://www.stackoverflow.com') |
- a内置的HTTP服务器。在当前的文件到服务目录:
1 | python -m SimpleHTTPServer 8000 |
- atexit
1 | >>> import atexit |
pow()还可以有效地计算(x**y)%z。
对于内置的
1 2 3 | >>> x, y, z = 1234567890, 2345678901, 17 >>> pow(x, y, z) # almost instantaneous 6 |
相比之下,
您可以用zip轻松地转换数组。
1 2 3 | a = [(1,2), (3,4), (5,6)] zip(*a) # [(1, 3, 5), (2, 4, 6)] |
用不同的起始索引枚举
这个答案部分涵盖了
由于python 2.6,您可以在其第二个参数中为
1 2 3 4 5 | >>> l = ["spam","ham","eggs"] >>> list(enumerate(l)) >>> [(0,"spam"), (1,"ham"), (2,"eggs")] >>> list(enumerate(l, 1)) >>> [(1,"spam"), (2,"ham"), (3,"eggs")] |
我发现它非常有用的一个地方是,当我枚举对称矩阵的条目时。由于矩阵是对称的,所以我只需迭代上三角就可以节省时间,但在这种情况下,我必须在内部
1 2 3 | for ri, row in enumerate(matrix): for ci, column in enumerate(matrix[ri:], ri): # ci now refers to the proper column index |
奇怪的是,
可以使用属性使类接口更严格。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | class C(object): def __init__(self, foo, bar): self.foo = foo # read-write property self.bar = bar # simple attribute def _set_foo(self, value): self._foo = value def _get_foo(self): return self._foo def _del_foo(self): del self._foo # any of fget, fset, fdel and doc are optional, # so you can make a write-only and/or delete-only property. foo = property(fget = _get_foo, fset = _set_foo, fdel = _del_foo, doc = 'Hello, I am foo!') class D(C): def _get_foo(self): return self._foo * 2 def _set_foo(self, value): self._foo = value / 2 foo = property(fget = _get_foo, fset = _set_foo, fdel = C.foo.fdel, doc = C.foo.__doc__) |
在python 2.6和3.0中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class C(object): def __init__(self, foo, bar): self.foo = foo # read-write property self.bar = bar # simple attribute @property def foo(self): '''Hello, I am foo!''' return self._foo @foo.setter def foo(self, value): self._foo = value @foo.deleter def foo(self): del self._foo class D(C): @C.foo.getter def foo(self): return self._foo * 2 @foo.setter def foo(self, value): self._foo = value / 2 |
要了解属性如何工作的更多信息,请参阅描述符。
许多人不知道"你"的功能。这是一个伟大的方式找到什么对象可以从解释器。例如,如果你想看到一个列表的所有字符串的方法:
1 2 3 | >>> dir("foo") ['__add__', '__class__', '__contains__', (snipped a bunch), 'title', 'translate', 'upper', 'zfill'] |
然后,如果你想要更多的信息关于一个特定的方法,你可以调用它的"帮助"。
1 2 3 4 5 6 7 | >>> help("foo".upper) Help on built-in function upper: upper(...) S.upper() -> string Return a copy of the string S converted to uppercase. |
设置/冻结
可能一个容易被忽视的python内置组件是"set/frozenset"。
当您有这样的列表时很有用,[1,2,1,1,2,3,4]并且只需要这样的唯一性[1,2,3,4]。
使用set()可以得到:
1 2 3 4 5 6 7 8 9 10 11 12 | >>> x = [1,2,1,1,2,3,4] >>> >>> set(x) set([1, 2, 3, 4]) >>> >>> for i in set(x): ... print i ... 1 2 3 4 |
当然,要在列表中获得唯一的数量:
1 2 | >>> len(set([1,2,1,1,2,3,4])) 4 |
还可以使用set().is subset()查找列表是否是其他列表的子集:
1 2 | >>> set([1,2,3,4]).issubset([0,1,2,3,4,5]) True |
从python 2.7和3.0开始,可以使用大括号创建集合:
1 | myset = {1,2,3,4} |
以及集合理解:
1 | {x for x in stuff} |
有关详细信息:http://docs.python.org/library/stdtypes.html设置
内置base64、zlib和rot13编解码器
字符串有
1 2 3 | >>> s = 'a' * 100 >>> s.encode('zlib') 'x\x9cKL\xa4=\x00\x00zG%\xe5' |
同样,您可以对base64进行编码和解码:
1 2 3 4 5 6 | >>> 'Hello world'.encode('base64') 'SGVsbG8gd29ybGQ= ' >>> 'SGVsbG8gd29ybGQ= '.decode('base64') 'Hello world' |
当然,您也可以选择13:
1 2 | >>> 'Secret message'.encode('rot13') 'Frperg zrffntr' |
口译员中的口译员
标准库的代码模块允许您在程序中包含自己的read eval打印循环,或者运行一个完整的嵌套解释器。例如(从这里复制了我的示例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | $ python Python 2.5.1 (r251:54863, Jan 17 2008, 19:35:17) [GCC 4.0.1 (Apple Inc. build 5465)] on darwin Type"help","copyright","credits" or"license" for more information. >>> shared_var ="Set in main console" >>> import code >>> ic = code.InteractiveConsole({ 'shared_var': shared_var }) >>> try: ... ic.interact("My custom console banner!") ... except SystemExit, e: ... print"Got SystemExit!" ... My custom console banner! >>> shared_var 'Set in main console' >>> shared_var ="Set in sub-console" >>> import sys >>> sys.exit() Got SystemExit! >>> shared_var 'Set in main console' |
这对于您希望接受来自用户的脚本化输入或实时查询虚拟机状态的情况非常有用。
TurboGears使用一个Webconsole,从中您可以查询您的实时Web应用程序的状态,从而达到了非常好的效果。
1 2 3 4 5 6 | >>> from functools import partial >>> bound_func = partial(range, 0, 10) >>> bound_func() [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> bound_func(2) [0, 2, 4, 6, 8] |
不是真正的隐藏功能,但部分功能对于功能的后期评估非常有用。
可以根据需要将初始调用中的任意多个或任意少个参数绑定到分部,并在以后使用任何剩余参数调用它(在本例中,我将begin/end参数绑定到range,但第二次使用step参数调用它)。
请参阅文档。
在调试复杂数据结构时,pprint模块非常方便。
从文件中引用。
1 2 3 4 5 6 7 8 9 10 11 | >>> import pprint >>> stuff = sys.path[:] >>> stuff.insert(0, stuff) >>> pprint.pprint(stuff) [<Recursion on list with id=869440>, '', '/usr/local/lib/python1.5', '/usr/local/lib/python1.5/test', '/usr/local/lib/python1.5/sunos5', '/usr/local/lib/python1.5/sharedmodules', '/usr/local/lib/python1.5/tkinter'] |
Python已经开始了
…由外部纯python模块实现:)
1 2 3 4 5 6 7 8 9 | from goto import goto, label for i in range(1, 10): for j in range(1, 20): for k in range(1, 30): print i, j, k if k == 3: goto .end # breaking out from a deeply nested loop label .end print"Finished" |
dict的构造函数接受关键字参数:
1 2 | >>> dict(foo=1, bar=2) {'foo': 1, 'bar': 2} |
序列乘法和反射操作数
1 2 3 4 5 6 7 8 | >>> 'xyz' * 3 'xyzxyzxyz' >>> [1, 2] * 3 [1, 2, 1, 2, 1, 2] >>> (1, 2) * 3 (1, 2, 1, 2, 1, 2) |
我们用反射(交换)操作数得到相同的结果
1 2 | >>> 3 * 'xyz' 'xyzxyzxyz' |
工作原理如下:
1 2 | >>> s = 'xyz' >>> num = 3 |
要计算表达式s*num解释器,调用s.uuuuu muluuuuuuu(num)
1 2 3 4 5 | >>> s * num 'xyzxyzxyz' >>> s.__mul__(num) 'xyzxyzxyz' |
要计算表达式num*s解释器,请调用num。
1 2 3 4 5 | >>> num * s 'xyzxyzxyz' >>> num.__mul__(s) NotImplemented |
如果调用返回NotImplemented,则解释程序调用如果操作数的类型不同,则返回操作s。
1 2 | >>> s.__rmul__(num) 'xyzxyzxyz' |
请参见http://docs.python.org/reference/datamodel.html object.rmul
Interleaving
1 2 | >>> [(x, y) for x in range(4) if x % 2 == 1 for y in range(4)] [(1, 0), (1, 1), (1, 2), (1, 3), (3, 0), (3, 1), (3, 2), (3, 3)] |
直到我学会哈斯克尔我才意识到这一点。
模块运算符中的getter函数
模块
python库文档中的第6.7章
显然,反重力模块。XKCDα353
tuple解包:
1 2 3 4 5 6 7 | >>> (a, (b, c), d) = [(1, 2), (3, 4), (5, 6)] >>> a (1, 2) >>> b 3 >>> c, d (4, (5, 6)) |
更模糊的是,您可以在函数参数中这样做(在python 2.x中;python 3.x将不再允许这样做):
1 2 3 4 | >>> def addpoints((x1, y1), (x2, y2)): ... return (x1+x2, y1+y2) >>> addpoints((5, 0), (3, 5)) (8, 5) |
python解释器
1 | >>> |
也许不鲜为人知,但肯定是我最喜欢的Python特性之一。
简单的:
1 2 3 4 5 | >>> 'str' in 'string' True >>> 'no' in 'yes' False >>> |
关于Python,我很喜欢它,我看到过很多不太像Python的习语:
1 2 | if 'yes'.find("no") == -1: pass |
在构建列表时引用列表理解…
您可以引用一个列表理解,因为它是由符号"[1]"构建的。例如,下面的函数唯一地表示元素列表,而不通过引用其列表理解来更改它们的顺序。
1 2 | def unique(my_list): return [x for x in my_list if x not in locals()['_[1]']] |
sort函数Python元组(即:正确使用熟悉的lexicographical Order):
1 2 3 | a = [(2,"b"), (1,"a"), (2,"a"), (3,"c")] print sorted(a) #[(1, 'a'), (2, 'a'), (2, 'b'), (3, 'c')] |
有用的,如果你想排序列表,然后后时代的人的名字。
解包语法已在最新版本中升级,如示例中所示。
1 2 3 4 5 6 7 8 9 | >>> a, *b = range(5) >>> a, b (0, [1, 2, 3, 4]) >>> *a, b = range(5) >>> a, b ([0, 1, 2, 3], 4) >>> a, *b, c = range(5) >>> a, b, c (0, [1, 2, 3], 4) |
我个人喜欢这三个不同的引语
1 2 3 4 5 | str ="I'm a string 'but still I can use quotes' inside myself!" str =""" For some messy multi line strings. Such as <html> <head> ... </head>""" |
也很酷:不必逃避正则表达式,使用原始字符串来避免可怕的反斜杠沙拉:
1 2 3 4 | str2 = r" " print str2 >> |
元类
当然:-)什么是Python中的元类?
发电机
我认为很多刚开始的Python开发人员都忽略了生成器,而没有真正了解它们的用途或对它们的能力有任何了解。直到我读到大卫·M·比兹利关于发电机的Pycon演示(这里有),我才意识到它们有多有用(本质上是真的)。这个演示说明了对我来说是一种全新的编程方式,我向任何不了解生成器的人推荐它。
隐式连接:
1 2 | >>> print"Hello""World" Hello World |
当要使长文本适合脚本中的多行时很有用:
1 2 | hello ="Greaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Hello" \ "Word" |
或
1 2 | hello = ("Greaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Hello" "Word") |
使用交互式shell时,"_uu"包含最后一个打印项的值:
1 2 3 4 5 | >>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> _ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> |
python中的
1 2 3 4 5 6 7 8 9 10 11 12 13 | import unittest, textwrap class XMLTests(unittest.TestCase): def test_returned_xml_value(self): returned_xml = call_to_function_that_returns_xml() expected_value = textwrap.dedent("""\ <?xml version="1.0" encoding="utf-8"?> <root_node> <my_node>my_content</my_node> </root_node> """) self.assertEqual(expected_value, returned_xml) |
零参数和变参数lambdas
lambda函数通常用于将一个值快速转换为另一个值,但也可用于将值包装在函数中:
1 2 3 | >>> f = lambda: 'foo' >>> f() 'foo' |
他们还可以接受通常的
1 2 3 | >>> g = lambda *args, **kwargs: args[0], kwargs['thing'] >>> g(1, 2, 3, thing='stuff') (1, 'stuff') |
使用关键字参数作为赋值
有时,人们希望根据一个或多个参数构建一系列函数。但是,这很容易导致闭包引用相同的对象和值:
1 2 3 4 5 6 7 8 | funcs = [] for k in range(10): funcs.append( lambda: k) >>> funcs[0]() 9 >>> funcs[7]() 9 |
通过将lambda表达式转换为仅依赖于其参数的函数,可以避免此行为。关键字参数存储绑定到它的当前值。函数调用不必更改:
1 2 3 4 5 6 7 8 | funcs = [] for k in range(10): funcs.append( lambda k = k: k) >>> funcs[0]() 0 >>> funcs[7]() 7 |
mod与负数一起正常工作
-1%5应该是4,而不是其他语言如javascript中的-1。这使得python中的"wraporaund windows"更干净,只需执行以下操作:
1 | index = (index + increment) % WINDOW_SIZE |
不是很隐蔽,但函数具有以下属性:
1 2 3 4 5 6 | def doNothing(): pass doNothing.monkeys = 4 print doNothing.monkeys 4 |
字典中无限递归的良好处理:
1 2 3 4 5 6 | >>> a = {} >>> b = {} >>> a['b'] = b >>> b['a'] = a >>> print a {'b': {'a': {...}}} |
分配和删除切片:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | >>> a = range(10) >>> a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> a[:5] = [42] >>> a [42, 5, 6, 7, 8, 9] >>> a[:1] = range(5) >>> a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> del a[::2] >>> a [1, 3, 5, 7, 9] >>> a[::2] = a[::-2] >>> a [9, 3, 5, 7, 1] |
注意:当分配给扩展片(
将元组传递给内置函数
许多python函数接受元组,但看起来也不是这样。例如,要测试变量是否为数字,可以执行以下操作:
1 2 | if isinstance (number, float) or isinstance (number, int): print"yaay" |
但如果你超过我们,这看起来更干净:
1 2 | if isinstance (number, (float, int)): print"yaay" |
三元运算符
1 2 3 4 | >>> 'ham' if True else 'spam' 'ham' >>> 'ham' if False else 'spam' 'spam' |
这是添加到现有2.5,你可以使用:
1 2 3 4 | >>> True and 'ham' or 'spam' 'ham' >>> False and 'ham' or 'spam' 'spam' |
然而,如果你想与我们的价值观被视为假,有一个差分:
1 2 3 4 | >>> [] if True else 'spam' [] >>> True and [] or 'spam' 'spam' |
第一类函数
这并不是一个隐藏的特性,但是函数是第一类对象的事实是非常好的。你可以像其他变量一样传递它们。
1 2 3 4 5 6 7 | >>> def jim(phrase): ... return 'Jim says,"%s".' % phrase >>> def say_something(person, phrase): ... print person(phrase) >>> say_something(jim, 'hey guys') 'Jim says,"hey guys".' |
用负阶跃来逆转一个不可测的
1 2 3 4 5 6 7 8 9 | >>> s ="Hello World" >>> s[::-1] 'dlroW olleH' >>> a = (1,2,3,4,5,6) >>> a[::-1] (6, 5, 4, 3, 2, 1) >>> a = [5,4,3,2,1] >>> a[::-1] [1, 2, 3, 4, 5] |
可以说,这本身不是一个编程特性,但是非常有用,所以我还是要发布它。
1 | $ python -m http.server |
…接着是其他地方的
如果仍在运行旧版(2.x)的python:
1 | $ python -m SimpleHTTPServer |
您还可以指定一个端口,例如
不是"隐藏",但非常有用,不常用
像这样快速创建字符串连接函数
1 2 3 4 5 | comma_join =",".join semi_join =";".join print comma_join(["foo","bar","baz"]) 'foo,bar,baz |
和
能够创建比引号更优雅的字符串列表,逗号混乱。
1 | l = ["item1","item2","item3"] |
被替换
1 | l ="item1 item2 item3".split() |
从python 3.1(2.7)字典和集合理解得到支持:
1 2 | { a:a for a in range(10) } { a for a in range(10) } |
对迭代器的多个引用
可以使用列表乘法创建对同一迭代器的多个引用:
1 2 3 4 5 6 7 8 | >>> i = (1,2,3,4,5,6,7,8,9,10) # or any iterable object >>> iterators = [iter(i)] * 2 >>> iterators[0].next() 1 >>> iterators[1].next() 2 >>> iterators[0].next() 3 |
这可用于将ITerable分组为块,例如,在本例中,来自
1 2 3 4 | def grouper(n, iterable, fillvalue=None): "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" args = [iter(iterable)] * n return izip_longest(fillvalue=fillvalue, *args) |
python可以理解任何一种Unicode数字,而不仅仅是ASCII数字:
1 2 3 4 5 6 7 8 9 | >>> s = u'10585' >>> s u'\uff11\uff10\uff15\uff18\uff15' >>> print s 10585 >>> int(s) 10585 >>> float(s) 10585.0 |
操作系统模块
您可以直接操作模块缓存,使模块可用或不可用,具体如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | >>> import sys >>> import ham Traceback (most recent call last): File"<stdin>", line 1, in <module> ImportError: No module named ham # Make the 'ham' module available -- as a non-module object even! >>> sys.modules['ham'] = 'ham, eggs, saussages and spam.' >>> import ham >>> ham 'ham, eggs, saussages and spam.' # Now remove it again. >>> sys.modules['ham'] = None >>> import ham Traceback (most recent call last): File"<stdin>", line 1, in <module> ImportError: No module named ham |
这甚至适用于可用的模块,在某种程度上也适用于已导入的模块:
1 2 3 4 5 6 7 8 9 10 | >>> import os # Stop future imports of 'os'. >>> sys.modules['os'] = None >>> import os Traceback (most recent call last): File"<stdin>", line 1, in <module> ImportError: No module named os # Our old imported module is still available. >>> os <module 'os' from '/usr/lib/python2.5/os.pyc'> |
如最后一行所示,更改sys.modules只会影响未来的
迭代工具
这个模块经常被忽视。下面的示例使用
1 2 3 4 | >>> from itertools import * >>> l = [[1, 2], [3, 4]] >>> list(chain(*l)) [1, 2, 3, 4] |
更多应用程序请参见http://docs.python.org/library/itertools.html食谱。
1 2 | class Point(object): __slots__ = ('x', 'y') |
现在这个对象显然有两个属性。现在,我们可以创建它的一个实例,并以这种方式构建它的dict:
1 2 3 4 5 | >>> p = Point() >>> p.x = 3 >>> p.y = 5 >>> dict((k, getattr(p, k)) for k in p.__slots__) {'y': 5, 'x': 3} |
但是,如果点是子类的,并且添加了新的槽,这将不起作用。然而,python自动实现
1 2 | >>> p.__reduce_ex__(2)[2][1] {'y': 5, 'x': 3} |
您可以通过查看它的模块属性来询问任何对象它来自哪个模块。例如,如果您正在命令行中进行试验,并且导入了很多东西,那么这很有用。
同样,您可以通过查看模块的"文件"属性来询问模块的来源。这在调试路径问题时很有用。
猜测整数基数
1 2 3 4 5 6 7 8 9 10 | >>> int('10', 0) 10 >>> int('0x10', 0) 16 >>> int('010', 0) # does not work on Python 3.x 8 >>> int('0o10', 0) # Python >=2.6 and Python 3.x 8 >>> int('0b10', 0) # Python >=2.6 and Python 3.x 2 |
一些内置的收藏夹map()、reduce()和filter()。一切都非常迅速和强大。
一言以蔽之:伊普生
制表符内省、精美打印、
在子类中扩展属性(定义为描述符)
有时它对于扩展(修改)子类中描述符"返回"的值很有用。使用
1 2 3 4 5 6 7 8 9 | class A(object): @property def prop(self): return {'a': 1} class B(A): @property def prop(self): return dict(super(B, self).prop, b=2) |
将其存储在
1 2 | >>> B().prop {'a': 1, 'b': 2} |
你可以建立一套词典从A - 2序列的长度。当你的手机有一个列表和列表中的值的数组。
1 2 3 4 5 6 7 | >>> dict([ ('foo','bar'),('a',1),('b',2) ]) {'a': 1, 'b': 2, 'foo': 'bar'} >>> names = ['Bob', 'Marie', 'Alice'] >>> ages = [23, 27, 36] >>> dict(zip(names, ages)) {'Alice': 36, 'Bob': 23, 'Marie': 27} |
Python的一种轻微的畸形。将字符串列表连接在一起的正常快速方法是,
1 | ''.join(list_of_strings) |
创建枚举
在python中,可以这样做以快速创建枚举:
1 2 3 | >>> FOO, BAR, BAZ = range(3) >>> FOO 0 |
但"枚举"不必具有整数值。你甚至可以这样做:
1 2 3 4 5 | class Colors(object): RED, GREEN, BLUE, YELLOW = (255,0,0), (0,255,0), (0,0,255), (0,255,255) #now Colors.RED is a 3-tuple that returns the 24-bit 8bpp RGB #value for saturated red |
对象数据模型
您可以为自己的类重写语言中的任何运算符。有关完整列表,请参阅此页。一些例子:
您可以覆盖任何操作符(
* + - / // % ^ == < > <= >= . 等)。所有这些都是通过覆盖对象中的__mul__ 、__add__ 等来完成的。你甚至可以覆盖像__rmul__ 这样的东西来分别处理your_object*something_else 和something_else*your_object 。. 是属性访问(a.b ),可以通过使用__getattr__ 覆盖来处理任意b 。这里还包括使用__call__ 的a(…) 。您可以创建自己的切片语法(
a[stuff] ),它非常复杂,并且与列表中使用的标准语法(numpy在其数组中有一个很好的例子说明了这一点)有很大的不同,可以使用您喜欢的任何组合, 、: 和… ,使用切片对象。特别处理语言中的许多关键字所发生的事情。包括:
del 、in 、import 、not 。处理用对象调用许多内置函数时发生的情况。标准的
__int__ 、__str__ 等都在这里,但是__len__ 、__reversed__ 、__abs__ 和三个参数__pow__ 也在这里。
在运行时更改函数标签:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> class foo: ... def normal_call(self): print"normal_call" ... def call(self): ... print"first_call" ... self.call = self.normal_call >>> y = foo() >>> y.call() first_call >>> y.call() normal_call >>> y.call() normal_call ... |
假设您有一个来自外部源的字符串,它包含
1 2 3 4 5 6 | >>> print s Hello Stack\toverflow >>> print s.decode('string-escape') Hello Stack overflow |
另一个问题。您有一个普通的字符串,其中包含像
1 2 3 4 5 6 7 | >>> s = '\u041f\u0440\u0438\u0432\u0456\u0442, \u0441\u0432\u0456\u0442!' >>> print s \u041f\u0440\u0438\u0432\u0456\u0442, \u0441\u0432\u0456\u0442! >>> print unicode(s) \u041f\u0440\u0438\u0432\u0456\u0442, \u0441\u0432\u0456\u0442! >>> print unicode(s, 'unicode-escape') Прив?т, св?т! |
"解包"的功能参数。
1 2 3 4 5 | def foo(a, b, c): print a, b, c bar = (3, 14, 15) foo(*bar) |
当执行打印。
1 | 3 14 15 |
快速实例:
1 2 | for i in reversed([1, 2, 3]): print(i) |
生产:
1 2 3 | 3 2 1 |
但是,
Python禅
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | >>> import this The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those! |
动态添加的属性
如果您只想通过调用类向类中添加一些属性,那么这可能很有用。这可以通过重写在使用点操作数时调用的
1 2 3 4 | class Dummy(object): def __getattribute__(self, name): f = lambda: 'Hello with %s'%name return f |
当您实例化一个虚拟对象并执行一个方法调用时,您将得到以下内容:
1 2 3 | >>> d = Dummy() >>> d.b() 'Hello with b' |
最后,您甚至可以将属性设置为类,以便对其进行动态定义。如果您使用python web框架并希望通过解析属性的名称来进行查询,那么这将非常有用。
我在Github有一个要点,这里有一个简单的代码,它相当于一个朋友在Ruby上编写的代码。
当心!
绝密属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | >>> class A(object): pass >>> a = A() >>> setattr(a,"can't touch this", 123) >>> dir(a) ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',"can't touch this"] >>> a.can't touch this # duh File"<stdin>", line 1 a.can't touch this ^ SyntaxError: EOL while scanning string literal >>> getattr(a,"can't touch this") 123 >>> setattr(a,"__class__.__name__",":O") >>> a.__class__.__name__ 'A' >>> getattr(a,"__class__.__name__") ':O' |
用
1 2 3 4 5 6 | Python 2.7.1 (r271:86832, May 27 2011, 21:41:45) [GCC 4.2.1 (Apple Inc. build 5664)] on darwin Type"help","copyright","credits" or"license" for more information. >>> l = [[1, 2, 3], [4, 5], [6], [7, 8, 9]] >>> sum(l, []) [1, 2, 3, 4, 5, 6, 7, 8, 9] |
namedTuple是一个元组
1 2 3 4 5 6 | >>> node = namedtuple('node',"a b") >>> node(1,2) + node(5,6) (1, 2, 5, 6) >>> (node(1,2), node(5,6)) (node(a=1, b=2), node(a=5, b=6)) >>> |
更多的实验来回应评论:
1 2 3 4 5 6 7 8 9 10 11 | >>> from collections import namedtuple >>> from operator import * >>> mytuple = namedtuple('A',"a b") >>> yourtuple = namedtuple('Z',"x y") >>> mytuple(1,2) + yourtuple(5,6) (1, 2, 5, 6) >>> q = [mytuple(1,2), yourtuple(5,6)] >>> q [A(a=1, b=2), Z(x=5, y=6)] >>> reduce(operator.__add__, q) (1, 2, 5, 6) |
因此,
博格模式
这是亚历克斯·马泰利的杀手。
EDOCX1[22]的值可以在任何情况下重新分配,并且所有值都将更新,您甚至可以重新分配整个dict。borg是完美的名称,请在此处阅读更多信息。
1 2 3 4 5 | class Borg: __shared_state = {'foo': 'bar'} def __init__(self): self.__dict__ = self.__shared_state # rest of your class here |
这非常适合共享eventlet.greenpool来控制并发性。
在python中需要解压
有人在博客中提到python没有unzip函数可用于zip()。解压是直接计算的,因为:
1 2 3 4 | >>> t1 = (0,1,2,3) >>> t2 = (7,6,5,4) >>> [t1,t2] == zip(*zip(t1,t2)) True |
不过,经过深思熟虑,我还是希望有一个显式的unzip()。
创建包含相关数据的两个序列的字典
1 2 3 4 5 6 | In [15]: t1 = (1, 2, 3) In [16]: t2 = (4, 5, 6) In [17]: dict (zip(t1,t2)) Out[17]: {1: 4, 2: 5, 3: 6} |
pdb-python调试器
作为一个程序员,真正的程序开发首先需要的是一个调试器。python有一个内置的模块,称为pdb(对于"python debugger",当然是!).
http://docs.python.org/library/pdb.html网站
线程。枚举()提供对系统中所有线程对象的访问,并且sys .x CurrutyFraseMe()返回系统中所有线程的当前堆栈帧,因此将两者结合起来,得到Java样式堆栈转储:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def dumpstacks(signal, frame): id2name = dict([(th.ident, th.name) for th in threading.enumerate()]) code = [] for threadId, stack in sys._current_frames().items(): code.append(" # Thread: %s(%d)" % (id2name[threadId], threadId)) for filename, lineno, name, line in traceback.extract_stack(stack): code.append('File:"%s", line %d, in %s' % (filename, lineno, name)) if line: code.append(" %s" % (line.strip())) print" ".join(code) import signal signal.signal(signal.SIGQUIT, dumpstacks) |
在多线程python程序开始时执行此操作,您可以通过发送sigquit随时访问线程的当前状态。您也可以选择signal.sigusr1或signal.sigusr2。
见
原始字符串中的反斜杠仍然可以转义引号。看到这个:
1 2 | >>> print repr(r"aaa"bbb") 'aaa\"bbb' |
请注意,反斜杠和双引号都出现在最后一个字符串中。
因此,不能以反斜杠结束原始字符串:
1 2 3 4 | >>> print repr(r"C:") SyntaxError: EOL while scanning string literal >>> print repr(r"C:"") 'C:\"' |
这是因为实现原始字符串是为了帮助编写正则表达式,而不是为了编写Windows路径。在gotcha-backslashes的windows文件名中阅读关于这个的长讨论。
运算符可以作为函数调用:
1 2 | from operator import add print reduce(add, [1,2,3,4,5,6]) |
…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | In [1]: test = { 1 : 'a' } In [2]: test[2] --------------------------------------------------------------------------- <type 'exceptions.KeyError'> Traceback (most recent call last) <ipython console> in <module>() <type 'exceptions.KeyError'>: 2 In [3]: test.get( 2 ) In [4]: test.get( 1 ) Out[4]: 'a' In [5]: test.get( 2 ) == None Out[5]: True |
甚至在"场景"中指定:
1 2 | In [6]: test.get( 2, 'Some' ) == 'Some' Out[6]: True |
您可以使用
1 2 3 4 5 6 | >>> a = {} >>> b = a.setdefault('foo', 'bar') >>> a {'foo': 'bar'} >>> b 'bar |
重新加载模块启用"实时编码"样式。但是类实例不会更新。这就是为什么,以及如何绕过它。记住,一切,是的,一切都是一个物体。
1 2 3 4 5 | >>> from a_package import a_module >>> cls = a_module.SomeClass >>> obj = cls() >>> obj.method() (old method output) |
现在,您在一个_module.py中更改方法,并希望更新您的对象。
1 2 3 4 5 | >>> reload(a_module) >>> a_module.SomeClass is cls False # Because it just got freshly created by reload. >>> obj.method() (old method output) |
有一种方法可以更新它(但考虑使用剪刀运行它):
1 2 3 4 5 | >>> obj.__class__ is cls True # it's the old class object >>> obj.__class__ = a_module.SomeClass # pick up the new class >>> obj.method() (new method output) |
这是"用剪刀运行",因为对象的内部状态可能与新类期望的不同。这适用于非常简单的情况,但除此之外,
列表中的无限递归
1 2 3 4 5 6 7 8 | >>> a = [1,2] >>> a.append(a) >>> a [1, 2, [...]] >>> a[2] [1, 2, [...]] >>> a[2][2][2][2][2][2][2][2][2] == a True |
检查模块也是一个很酷的功能。
舍入整数:python有round函数,它返回double类型的数字:
1 2 3 4 5 6 | >>> print round(1123.456789, 4) 1123.4568 >>> print round(1123.456789, 2) 1123.46 >>> print round(1123.456789, 0) 1123.0 |
这个函数有一个奇妙的魔力:
1 2 3 4 | >>> print round(1123.456789, -1) 1120.0 >>> print round(1123.456789, -2) 1100.0 |
如果结果需要整数,请使用int转换类型:
1 2 3 4 | >>> print int(round(1123.456789, -2)) 1100 >>> print int(round(8359980, -2)) 8360000 |
谢谢你,格雷戈。
操作递归限制
获取或设置sys.getRecursionLimit()和sys.setRecursionLimit()的最大递归深度。
我们可以限制它以防止由无限递归引起的堆栈溢出。
能够替换文件删除、文件打开等内容——直接操作语言库。这在测试时是一个巨大的优势。你不必把所有东西都包装在复杂的容器里。只需替换一个函数/方法就可以了。这也被称为猴子修补。
您可以用类来修饰函数-用类实例替换函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class countCalls(object): """ decorator replaces a function with a"countCalls" instance which behaves like the original function, but keeps track of calls >>> @countCalls ... def doNothing(): ... pass >>> doNothing() >>> doNothing() >>> print doNothing.timesCalled 2 """ def __init__ (self, functionToTrack): self.functionToTrack = functionToTrack self.timesCalled = 0 def __call__ (self, *args, **kwargs): self.timesCalled += 1 return self.functionToTrack(*args, **kwargs) |
如果在序列的最后一个元素之后找到,python 2.x将忽略逗号:
1 2 3 4 | >>> a_tuple_for_instance = (0,1,2,3,) >>> another_tuple = (0,1,2,3) >>> a_tuple_for_instance == another_tuple True |
尾随逗号导致单个带圆括号元素被视为序列:
1 | >>> a_tuple_with_one_element = (8,) |
切片和易变性
复制列表
1 2 3 4 5 6 7 8 | >>> x = [1,2,3] >>> y = x[:] >>> y.pop() 3 >>> y [1, 2] >>> x [1, 2, 3] |
替换列表
1 2 3 4 5 | >>> x = [1,2,3] >>> y = x >>> y[:] = [4,5,6] >>> x [4, 5, 6] |
嵌套函数参数重新绑定
1 2 3 4 5 | def create_printers(n): for i in xrange(n): def printer(i=i): # Doesn't work without the i=i print i yield printer |
切成薄片。这个筛子的埃拉托斯滕斯产生一个列表,要么有素数或0。元素在循环中的切片分配为0'd。
1 2 3 4 5 6 7 8 | def eras(n): last = n + 1 sieve = [0,0] + list(range(2, last)) sqn = int(round(n ** 0.5)) it = (i for i in xrange(2, sqn + 1) if sieve[i]) for i in it: sieve[i*i:last:i] = [0] * (n//i - i + 1) return filter(None, sieve) |
要工作,必须在左侧的切片的右侧指定一个长度相同的列表。
内置方法或函数不实现描述符协议,这使得不可能执行如下操作:
1 2 3 4 5 6 7 | >>> class C(object): ... id = id ... >>> C().id() Traceback (most recent call last): File"<stdin>", line 1, in <module> TypeError: id() takes exactly one argument (0 given) |
但是,您可以创建一个小的绑定描述符,使这成为可能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> from types import MethodType >>> class bind(object): ... def __init__(self, callable): ... self.callable = callable ... def __get__(self, obj, type=None): ... if obj is None: ... return self ... return MethodType(self.callable, obj, type) ... >>> class C(object): ... id = bind(id) ... >>> C().id() 7414064 |
可以用元类重写类的MRO
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | >>> class A(object): ... def a_method(self): ... print("A") ... >>> class B(object): ... def b_method(self): ... print("B") ... >>> class MROMagicMeta(type): ... def mro(cls): ... return (cls, B, object) ... >>> class C(A, metaclass=MROMagicMeta): ... def c_method(self): ... print("C") ... >>> cls = C() >>> cls.c_method() C >>> cls.a_method() Traceback (most recent call last): File"<stdin>", line 1, in <module> AttributeError: 'C' object has no attribute 'a_method' >>> cls.b_method() B >>> type(cls).__bases__ (<class '__main__.A'>,) >>> type(cls).__mro__ (<class '__main__.C'>, <class '__main__.B'>, <class 'object'>) |
它可能是出于一个很好的原因而隐藏起来的。:)
除HaridsV之前提到的内容外:
1 2 3 | >>> foo = bar = baz = 1 >>> foo, bar, baz (1, 1, 1) |
也可以这样做:
1 2 3 | >>> foo, bar, baz = 1, 2, 3 >>> foo, bar, baz (1, 2, 3) |
暴露可变缓冲区
使用python buffer协议在python(2.5/2.6)中公开可变的面向字节的缓冲区。
(对不起,这里没有密码。需要使用低级C API或现有适配器模块)。
_ _ getattr _ _()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class FogBugz: ... def __getattr__(self, name): # Let's leave the private stuff to Python if name.startswith("__"): raise AttributeError("No such attribute '%s'" % name) if not self.__handlerCache.has_key(name): def handler(**kwargs): return self.__makerequest(name, **kwargs) self.__handlerCache[name] = handler return self.__handlerCache[name] ... |
当有人呼叫
集合理解
1 2 | >>> {i**2 for i in range(5)} set([0, 1, 4, 16, 9]) |
python文档
维基百科条目
听写理解
1 2 | >>> {i: i**2 for i in range(5)} {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} |
python文档
维基百科条目
列表解析
列表推导式
比较更传统的(没有列表理解):
1 2 3 4 | foo = [] for x in xrange(10): if x % 2 == 0: foo.append(x) |
到:
1 | foo = [x for x in xrange(10) if x % 2 == 0] |
Python习语
尽管声明
1 | x = 3 if (y == 1) else 2 |
等于
1 | x = y == 1 and 3 or 2 |
如果你使用
1 | x = 0 if True else 1 # sets x equal to 0 |
因此不等于
1 | x = True and 0 or 1 # sets x equal to 1 |
更多关于正确方法的信息,请参见python的隐藏特性。
我不确定这在python文档中的位置(或者是否在其中),但是对于python 2.x(至少2.5和2.6,我刚刚尝试过),可以用parenthenses调用
例子:
另外,可以在python 2和3中使用parenthenses调用
parenthense也可以与其他语句和运算符一起使用。
编辑:把parenthenses放在
1 2 3 4 5 | >>> (not 1) == 9 False >>> not(1) == 9 True |
对于某些值(我认为它不是有效的标识符名称),这也可以工作,如下所示:
简单的内置基准测试工具
python标准库提供了一个非常易于使用的基准模块,叫做"timeit"。您甚至可以从命令行使用它来查看哪种语言构造最快。
例如。,
1 2 3 4 5 | % python -m timeit 'r = range(0, 1000)' 'for i in r: pass' 10000 loops, best of 3: 48.4 usec per loop % python -m timeit 'r = xrange(0, 1000)' 'for i in r: pass' 10000 loops, best of 3: 37.4 usec per loop |
如果在类上使用描述符,python将完全绕过该键的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> class User(object): ... def _get_username(self): ... return self.__dict__['username'] ... def _set_username(self, value): ... print 'username set' ... self.__dict__['username'] = value ... username = property(_get_username, _set_username) ... del _get_username, _set_username ... >>> u = User() >>> u.username ="foo" username set >>> u.__dict__ {'username': 'foo'} |
这有助于保持
这里有两个复活节彩蛋:
一个在python本身:
1 2 | >>> import __hello__ Hello world... |
在
通过查看
1 | 'werkzeug._internal': ['_easteregg'] |
如果你有点好奇,这会让你看看
因此,要显示这个复活节彩蛋,您似乎需要在
1 2 3 4 5 6 7 8 | from werkzeug import Request, Response, run_simple from werkzeug import _easteregg @Request.application def application(request): return Response('Hello World!') run_simple('localhost', 8080, _easteregg(application)) |
现在,如果您运行应用程序并访问http://localhost:8080/?麦加巴查库,你应该看看复活节彩蛋。
MonkeyPatching对象
python中的每个对象都有一个
1 2 3 4 5 6 7 | class Foo(object): def __init__(self, arg1, arg2, **kwargs): #do stuff with arg1 and arg2 self.__dict__.update(kwargs) f = Foo('arg1', 'arg2', bar=20, baz=10) #now f is a Foo object with two extra attributes |
这可以用来任意地向对象添加属性和函数。这也可以用来创建一个快速和肮脏的
1 2 3 4 5 | class struct(object): def __init__(**kwargs): self.__dict__.update(kwargs) s = struct(foo=10, bar=11, baz="i'm a string!') |
1 2 3 4 | try: return obj.attribute except AttributeError: return default |
但
这对鸭子打字很有用。也许你有这样的东西:
1 2 3 4 5 6 | class MyThing: pass class MyOtherThing: pass if isinstance(obj, (MyThing, MyOtherThing)): process(obj) |
(btw,
当你做一种新的东西时,你需要在它出现的任何地方把它添加到这个元组中。(这种构造在重新加载模块或以两个名称导入同一文件时也会导致问题。这种情况发生的次数比人们愿意承认的要多。)但相反,你可以说:
1 2 3 4 5 6 | class MyThing: processable = True class MyOtherThing: processable = True if getattr(obj, 'processable', False): process(obj) |
添加继承,它会变得更好:所有可处理对象的示例都可以继承自
1 2 | class Processable: processable = True |
但您不必说服所有人继承您的基类,只需设置一个属性。
太懒了,无法初始化字典中的每个字段?没问题:
在python>2.3中:
1 | from collections import defaultdict |
在python中<=2.3:
1 2 3 4 5 | def defaultdict(type_): class Dict(dict): def __getitem__(self, key): return self.setdefault(key, type_()) return Dict() |
在任何版本中:
1 2 3 | d = defaultdict(list) for stuff in lots_of_stuff: d[stuff.name].append(stuff) |
更新:
谢谢肯·阿诺德。我重新实现了更复杂的defaultdict版本。它的行为应该与标准库中的行为完全相同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | def defaultdict(default_factory, *args, **kw): class defaultdict(dict): def __missing__(self, key): if default_factory is None: raise KeyError(key) return self.setdefault(key, default_factory()) def __getitem__(self, key): try: return dict.__getitem__(self, key) except KeyError: return self.__missing__(key) return defaultdict(*args, **kw) |
进口反重力
特殊方法
绝对的力量!
python对于非常意外的事情有例外:
进口
这样可以在缺少lib时导入替代项
1 2 3 4 | try: import json except ImportError: import simplejson as json |
迭代
对于循环,在内部执行此操作,并捕获StopIteration:
1 2 3 4 5 | iter([]).next() Traceback (most recent call last): File"<pyshell#4>", line 1, in <module> iter(a).next() StopIteration |
断言
1 2 3 4 5 | >>> try: ... assert [] ... except AssertionError: ... print"This list should not be empty" This list should not be empty |
虽然这对于一个检查来说更为冗长,但是可以通过这种方式缩短将异常和具有相同错误消息的布尔运算符混合在一起的多个检查。
python3中的Unicode标识符:
1 2 3 4 5 | >>> 'Unicode字符_?????_Variable'.isidentifier() True >>> Unicode字符_?????_Variable='Python3 rules!' >>> Unicode字符_?????_Variable 'Python3 rules!' |
Access Dictionary elements as
attributes (properties). so if an
a1=AttrDict() has key 'name' ->
instead of a1['name'] we can easily
access name attribute of a1 using ->
a1.name
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class AttrDict(dict): def __getattr__(self, name): if name in self: return self[name] raise AttributeError('%s not found' % name) def __setattr__(self, name, value): self[name] = value def __delattr__(self, name): del self[name] person = AttrDict({'name': 'John Doe', 'age': 66}) print person['name'] print person.name person.name = 'Frodo G' print person.name del person.age print person |
通过一分钟的工作量,线程模块变得非常容易使用。这个修饰器更改一个函数,使它在自己的线程中运行,返回一个占位符类实例,而不是它的常规结果。您可以通过检查placeolder.result来探测答案,或者通过调用placeholder.wait result()来等待答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | def threadify(function): """ exceptionally simple threading decorator. Just: >>> @threadify ... def longOperation(result): ... time.sleep(3) ... return result >>> A= longOperation("A has finished") >>> B= longOperation("B has finished") A doesn't have a result yet: >>> print A.result None until we wait for it: >>> print A.awaitResult() A has finished we could also wait manually - half a second more should be enough for B: >>> time.sleep(0.5); print B.result B has finished """ class thr (threading.Thread,object): def __init__(self, *args, **kwargs): threading.Thread.__init__ ( self ) self.args, self.kwargs = args, kwargs self.result = None self.start() def awaitResult(self): self.join() return self.result def run(self): self.result=function(*self.args, **self.kwargs) return thr |
将解包与打印功能结合使用:
1 2 3 4 5 | # in 2.6 <= python < 3.0, 3.0 + the print function is native from __future__ import print_function mylist = ['foo', 'bar', 'some other value', 1,2,3,4] print(*mylist) |
利用python的动态特性创建应用程序用python语法配置文件。例如,如果您有以下内容在配置文件中:
1 2 3 4 | { "name1":"value1", "name2":"value2" } |
然后你可以把它读成:
1 | config = eval(open("filename").read()) |
插入vs追加
不是功能,但可能很有趣
假设您想在列表中插入一些数据,然后反转它。最简单的是
1 2 3 4 5 | count = 10 ** 5 nums = [] for x in range(count): nums.append(x) nums.reverse() |
然后你会想:那从一开始就插入数字呢?所以:
1 2 3 4 | count = 10 ** 5 nums = [] for x in range(count): nums.insert(0, x) |
但速度慢了100倍!如果我们将count设置为10**6,它将慢1000倍;这是因为insert是o(n^2),而append是o(n)。
造成这种差异的原因是,每次调用insert时,insert都必须移动列表中的每个元素;append只需在列表的末尾添加元素(有时它必须重新分配所有内容,但速度仍然要快得多)。
对象实例的方法替换
可以替换已创建对象实例的方法。它允许您创建具有不同(特殊)功能的对象实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | >>> class C(object): ... def fun(self): ... print"C.a", self ... >>> inst = C() >>> inst.fun() # C.a method is executed C.a <__main__.C object at 0x00AE74D0> >>> instancemethod = type(C.fun) >>> >>> def fun2(self): ... print"fun2", self ... >>> inst.fun = instancemethod(fun2, inst, C) # Now we are replace C.a by fun2 >>> inst.fun() # ... and fun2 is executed fun2 <__main__.C object at 0x00AE74D0> |
如我们所知,在
或者,我们可以使用
1 2 3 4 5 6 7 | >>> def fun3(self): ... print"fun3", self ... >>> import new >>> inst.fun = new.instancemethod(fun3, inst, C) >>> inst.fun() fun3 <__main__.C object at 0x00AE74D0> |
节点:此解决方案不应用作继承机制的一般替换!但在某些特定情况下(调试、模拟),它可能非常方便。
警告:此解决方案不适用于内置类型和使用槽的新样式类。
模块导出其命名空间中的所有内容
包括从其他模块导入的名称!
1 2 3 | # this is"answer42.py" from operator import * from inspect import * |
现在测试模块中可导入的内容。
1 2 3 4 5 6 7 | >>> import answer42 >>> answer42.__dict__.keys() ['gt', 'imul', 'ge', 'setslice', 'ArgInfo', 'getfile', 'isCallable', 'getsourcelines', 'CO_OPTIMIZED', 'le', 're', 'isgenerator', 'ArgSpec', 'imp', 'lt', 'delslice', 'BlockFinder', 'getargspec', 'currentframe', 'CO_NOFREE', 'namedtuple', 'rshift', 'string', 'getframeinfo', '__file__', 'strseq', 'iconcat', 'getmro', 'mod', 'getcallargs', 'isub', 'getouterframes', 'isdatadescriptor', 'modulesbyfile', 'setitem', 'truth', 'Attribute', 'div', 'CO_NESTED', 'ixor', 'getargvalues', 'ismemberdescriptor', 'getsource', 'isMappingType', 'eq', 'index', 'xor', 'sub', 'getcomments', 'neg', 'getslice', 'isframe', '__builtins__', 'abs', 'getmembers', 'mul', 'getclasstree', 'irepeat', 'is_', 'getitem', 'indexOf', 'Traceback', 'findsource', 'ModuleInfo', 'ipow', 'TPFLAGS_IS_ABSTRACT', 'or_', 'joinseq', 'is_not', 'itruediv', 'getsourcefile', 'dis', 'os', 'iand', 'countOf', 'getinnerframes', 'pow', 'pos', 'and_', 'lshift', '__name__', 'sequenceIncludes', 'isabstract', 'isbuiltin', 'invert', 'contains', 'add', 'isSequenceType', 'irshift', 'types', 'tokenize', 'isfunction', 'not_', 'istraceback', 'getmoduleinfo', 'isgeneratorfunction', 'getargs', 'CO_GENERATOR', 'cleandoc', 'classify_class_attrs', 'EndOfBlock', 'walktree', '__doc__', 'getmodule', 'isNumberType', 'ilshift', 'ismethod', 'ifloordiv', 'formatargvalues', 'indentsize', 'getmodulename', 'inv', 'Arguments', 'iscode', 'CO_NEWLOCALS', 'formatargspec', 'iadd', 'getlineno', 'imod', 'CO_VARKEYWORDS', 'ne', 'idiv', '__package__', 'CO_VARARGS', 'attrgetter', 'methodcaller', 'truediv', 'repeat', 'trace', 'isclass', 'ior', 'ismethoddescriptor', 'sys', 'isroutine', 'delitem', 'stack', 'concat', 'getdoc', 'getabsfile', 'ismodule', 'linecache', 'floordiv', 'isgetsetdescriptor', 'itemgetter', 'getblock'] >>> from answer42 import getmembers >>> getmembers <function getmembers at 0xb74b2924> >>> |
这是不使用
在python中没有秘密;)
一切事物的第一类("一切都是一个物体"),以及由此造成的混乱。
1 2 3 4 5 6 7 8 9 10 11 | >>> x = 5 >>> y = 10 >>> >>> def sq(x): ... return x * x ... >>> def plus(x): ... return x + x ... >>> (sq,plus)[y>x](y) 20 |
最后一行创建一个包含两个函数的元组,然后计算y>x(true),并将其用作元组的索引(通过将其强制转换为int,1),然后使用参数y调用该函数并显示结果。
对于进一步的滥用,如果返回的对象带有索引(例如列表),则可以在末尾添加更多的方括号;如果内容可调用,则可以添加更多的圆括号等。对于额外的反常情况,使用类似这样的代码的结果作为另一个示例中的表达式(即,用此代码替换y>x):
1 | (sq,plus)[y>x](y)[4](x) |
这展示了python的两个方面——"一切都是一个对象"的哲学走到了极端,以及使用不当或构思不当的语言语法可能导致完全不可读、不可维护的意面代码,适合于一个表达式的方法。
解包的元组中的理解和表达的循环列表发电机:
1 2 3 | >>> l=[(1,2),(3,4)] >>> [a+b for a,b in l ] [3,7] |
本研究使用的密钥,迭代过成语词典:对数据)
1 2 3 | d = { 'x':'y', 'f':'e'} for name, value in d.items(): # one can also use iteritems() print"name:%s, value:%s" % (name,value) |
照片:
1 2 | name:x, value:y name:f, value:e |
可以将多个变量赋给同一个值
1 2 3 | >>> foo = bar = baz = 1 >>> foo, bar, baz (1, 1, 1) |
有助于以紧凑的方式将多个变量初始化为无。
一切都是动态的
"没有编译时间"。python中的一切都是运行时。模块是通过自上而下执行模块的源代码来"定义"的,就像脚本一样,得到的名称空间是模块的属性空间。同样,通过从上到下执行类主体来"定义"类,并且生成的命名空间是类的属性空间。类主体可以包含完全任意的代码——包括导入语句、循环和其他类语句。创建一个类、函数甚至模块"动态的",正如有时所要求的那样,并不难;事实上,这是不可能避免的,因为一切都是"动态的"。
如果您在应用程序中重命名了一个类,通过pickle加载用户保存的文件,并且其中一个重命名的类存储在用户的旧保存中,则无法加载到该pickle文件中。
但是,只需添加对类定义的引用,一切都很好:
例如,以前:
1 2 | class Bleh: pass |
现在,
1 2 | class Blah: pass |
因此,用户保存的pickled文件包含对bleh的引用,因为重命名而不存在bleh。修复?
1 | Bleh = Blah |
简单!
python有"private"变量
以双下划线开始但不是结束的变量变为私有变量,而不仅仅是通过约定。实际上,uuvar变成了classname_uvar,其中classname是创建变量的类。它们不是继承的,不能被重写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | >>> class A: ... def __init__(self): ... self.__var = 5 ... def getvar(self): ... return self.__var ... >>> a = A() >>> a.__var Traceback (most recent call last): File"", line 1, in AttributeError: A instance has no attribute '__var' >>> a.getvar() 5 >>> dir(a) ['_A__var', '__doc__', '__init__', '__module__', 'getvar'] >>> |
使用和或模拟第三运算符。
python中的和或运算符返回对象本身,而不是布尔值。因此:
1 2 3 4 5 6 7 8 9 | In [18]: a = True In [19]: a and 3 or 4 Out[19]: 3 In [20]: a = False In [21]: a and 3 or 4 Out[21]: 4 |
然而,Py2.5似乎添加了一个显式的三级运算符。
1 2 3 4 | In [22]: a = 5 if True else '6' In [23]: a Out[23]: 5 |
好吧,如果你确定你的真子句不会被评估为假的话,这个方法是有效的。例子:
1 2 3 4 5 6 7 8 9 10 11 12 | >>> def foo(): ... print"foo" ... return 0 ... >>> def bar(): ... print"bar" ... return 1 ... >>> 1 and foo() or bar() foo bar 1 |
要想把它弄好,你必须再多做一点:
1 2 3 | >>> (1 and [foo()] or [bar()])[0] foo 0 |
不过,这并不是很漂亮。如果您的Python版本支持它,请使用条件运算符。
1 2 3 | >>> foo() if True or bar() foo 0 |
虽然不是很Python,但你可以使用
说明:
This form is sometimes referred to as
"
first expression after the >> must
evaluate to a"file-like" object,
specifically an object that has a
write() method as described above.
With this extended form, the
subsequent expressions are printed to
this file object. If the first
expression evaluates toNone , then
sys.stdout is used as the file for
output.
1 | ** Using sets to reference contents in sets of frozensets** |
正如您可能知道的,集合是可变的,因此不可散列,因此,如果要生成一组集合(或将集合用作字典键),则需要使用frozenset:
1 2 3 4 5 | >>> fabc = frozenset('abc') >>> fxyz = frozenset('xyz') >>> mset = set((fabc, fxyz)) >>> mset {frozenset({'a', 'c', 'b'}), frozenset({'y', 'x', 'z'})} |
但是,可以只使用普通集测试成员身份并删除/丢弃成员:
1 2 3 4 5 6 | >>> abc = set('abc') >>> abc in mset True >>> mset.remove(abc) >>> mset {frozenset({'y', 'x', 'z'})} |
引用python标准库文档:
Note, the
elem argument to the__contains__() ,remove() , anddiscard()
methods may be a set. To support searching for an equivalent frozenset, the
elem set is temporarily mutated during the search and then restored. During
the search, theelem set should not be read or mutated since it does not
have a meaningful value.
不幸的是,或许令人吃惊的是,字典也并非如此:
1 2 3 4 5 6 7 | >>> mdict = {fabc:1, fxyz:2} >>> fabc in mdict True >>> abc in mdict Traceback (most recent call last): File"<interactive input>", line 1, in <module> TypeError: unhashable type: 'set' |
在布尔上下文对象
空元组,列表,和许多其他的转换,字符串对象是一个在布尔上下文(false等效和非等效"是一个真正的)。
1 2 3 4 5 6 7 | empty_tuple = () empty_list = [] empty_dict = {} empty_string = '' empty_set = set() if empty_tuple or empty_list or empty_dict or empty_string or empty_set: print 'Never happens!' |
这允许一个逻辑操作,它返回到operands不是真/假,这是有用的在一些情况:
1 2 | s = t or"Default value" # s will be assigned"Default value" # if t is false/empty/none |
功能支持。
生成器和生成器表达式,特别是。
Ruby再次成为这一主流,但Python也能做到这一点。库中没有Ruby那么普遍,Ruby太糟糕了,但是我更喜欢它的语法,它更简单。
因为它们并不是无所不在的,所以我没有看到那么多关于它们为什么有用的例子,但是它们允许我编写更干净、更高效的代码。
一次一屏打印多行字符串
在
1 | type(license)(0,open('textfile.txt').read(),0)() |
这将一次打印由若干行分割的文件内容:
1 2 3 4 5 6 | ... file row 21 file row 22 file row 23 Hit Return for more, or q (and Return) to quit: |
事实上,一切都是一个对象,因此是可扩展的。我可以将成员变量作为元数据添加到我定义的函数中:
1 2 3 4 | >>> def addInts(x,y): ... return x + y >>> addInts.params = ['integer','integer'] >>> addInts.returnType = 'integer' |
这对于编写动态单元测试非常有用,例如
私有方法和数据隐藏(封装)
在python中有一个常见的习惯用法,用来表示方法和其他类成员,这些方法和其他类成员的名称以下划线开头,并不打算成为类的外部API的一部分。这很方便,并且在实践中非常有效,但它给人的错误印象是,Python不支持私有代码和/或数据的真正封装。事实上,python自动为您提供了词汇闭包,这使得在实际情况需要时,以一种更加防弹的方式封装数据非常容易。下面是一个利用此技术的类的人为示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class MyClass(object): def __init__(self): privateData = {} self.publicData = 123 def privateMethod(k): print privateData[k] + self.publicData def privilegedMethod(): privateData['foo'] ="hello" privateMethod('foo') self.privilegedMethod = privilegedMethod def publicMethod(self): print self.publicData |
这里有一个人为的使用例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | >>> obj = MyClass() >>> obj.publicMethod() 123 >>> obj.publicData = 'World' >>> obj.publicMethod() World >>> obj.privilegedMethod() hello World >>> obj.privateMethod() Traceback (most recent call last): File"<stdin>", line 1, in <module> AttributeError: 'MyClass' object has no attribute 'privateMethod' >>> obj.privateData Traceback (most recent call last): File"<stdin>", line 1, in <module> AttributeError: 'MyClass' object has no attribute 'privateData' |
关键是,
在python 2.x中,拥有可变私有状态的唯一方法是使用可变对象(如本例中的dict)。许多人都说这有多烦人。python 3.x将通过引入pep 3104中描述的
测试密钥是否在dict中的简单方法:
1 2 3 4 5 6 7 8 | >>> 'key' in { 'key' : 1 } True >>> d = dict(key=1, key2=2) >>> if 'key' in d: ... print 'Yup' ... Yup |
标准python中的
用于测试目的。
我从
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | >>> import __hello__ Hello world... >>> type(__hello__) <type 'module'> >>> from __phello__ import spam Hello world... Hello world... >>> type(spam) <type 'module'> >>> help(spam) Help on module __phello__.spam in __phello__: NAME __phello__.spam FILE c:\python26\<frozen> |
类作为第一类对象(通过动态类定义显示)
注意闭包的使用。如果这个特殊的例子看起来像是解决问题的"正确"方法,请仔细重新考虑…好几次:)
1 2 3 4 5 6 7 8 9 10 | def makeMeANewClass(parent, value): class IAmAnObjectToo(parent): def theValue(self): return value return IAmAnObjectToo Klass = makeMeANewClass(str,"fred") o = Klass() print isinstance(o, str) # => True print o.theValue() # => fred |
不是一个隐藏的特性,而是一些有用的特性。
用于循环浏览列表对中的项
1 | for x, y in zip(s, s[1:]): |
1 2 3 4 | >>> float('infinity') inf >>> float('NaN') nan |
更多信息:
- http://docs.python.org/library/functions.html float
- http://www.python.org/dev/peps/pep-0754/
- python nan和inf值
关于Nick Johnson对属性类的实现(当然只是描述符的演示,而不是内置的替换),我将包括一个引发属性错误的setter:
1 2 3 4 5 6 7 8 9 10 11 | class Property(object): def __init__(self, fget): self.fget = fget def __get__(self, obj, type): if obj is None: return self return self.fget(obj) def __set__(self, obj, value): raise AttributeError, 'Read-only attribute' |
包含setter使其成为数据描述符,而不是方法/非数据描述符。数据描述符优先于实例字典。现在一个实例不能将不同的对象分配给属性名,并且尝试分配给属性会导致属性错误。
getattr内置函数:
1 2 3 4 5 6 7 8 9 10 | >>> class C(): def getMontys(self): self.montys = ['Cleese','Palin','Idle','Gilliam','Jones','Chapman'] return self.montys >>> c = C() >>> getattr(c,'getMontys')() ['Cleese', 'Palin', 'Idle', 'Gilliam', 'Jones', 'Chapman'] >>> |
如果要根据上下文分派函数,则非常有用。参见dive into python(此处)中的示例
内存管理
python动态分配内存并使用垃圾收集来恢复未使用的空间。一旦对象超出范围,并且没有其他变量引用它,它将被恢复。我不必担心缓冲区溢出和缓慢增长的服务器进程。内存管理也是其他动态语言的一个特性,但是Python做得很好。
当然,我们必须注意循环引用,并保持对不再需要的对象的引用,但是弱引用在这里有很大帮助。
完全不是隐藏的功能,但仍然很好:
1 2 3 | import os.path as op root_dir = op.abspath(op.join(op.dirname(__file__),"..")) |
操作路径时可保存大量字符!
曾经使用过xrange(int)而不是range(int)….它的内存使用率较低,并不真正依赖于整数的大小。哎呀!!不是很好吗?
如果在函数中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | >>> def f(): ... exec"a = 42" ... return a ... >>> def g(): ... a = 42 ... return a ... >>> import dis >>> dis.dis(f) 2 0 LOAD_CONST 1 ('a = 42') 3 LOAD_CONST 0 (None) 6 DUP_TOP 7 EXEC_STMT 3 8 LOAD_NAME 0 (a) 11 RETURN_VALUE >>> dis.dis(g) 2 0 LOAD_CONST 1 (42) 3 STORE_FAST 0 (a) 3 6 LOAD_FAST 0 (a) 9 RETURN_VALUE |
不是编程功能,但在将python与
1 | python -c"import os; print(os.getcwd());" |
请参见这里的python文档。在编写较长的Python脚本时需要注意的其他事项可以在本讨论中看到。
1 2 3 4 | >>> x=[1,1,2,'a','a',3] >>> y = [ _x for _x in x if not _x in locals()['_[1]'] ] >>> y [1, 2, 'a', 3] |
"locals()["[1]"]是正在创建的列表的"秘密名称"。当正在构建的列表状态影响后续的构建决策时非常有用。
python的位置和关键字扩展可以即时使用,而不仅仅是从存储列表中使用。
1 2 3 4 | l=lambda x,y,z:x+y+z a=1,2,3 print l(*a) print l(*[a[0],2,3]) |
对于这样的事情,它通常更有用:
1 2 | a=[2,3] l(*(a+[3])) |
使用map和reduce函数的map reduce
以这种方式创建一个简单的sumproduct:
1 2 | def sumprod(x,y): return reduce(lambda a,b:a+b, map(lambda a, b: a*b,x,y)) |
例子:
1 2 | In [2]: sumprod([1,2,3],[4,5,6]) Out[2]: 32 |
在python 2中,可以通过用反勾号将表达式括起来来生成表达式的字符串表示:
1 2 | >>> `sorted` '<built-in function sorted>' |
这在python 3.x中消失了。
脚本(和doctest字符串)的交互式调试
我不认为这是众所周知的,但是在任何Python脚本中添加这一行:
将导致PDB调试器在代码中的该点弹出运行光标。我认为,更鲜为人知的是,你可以在一个医生测试中使用同一行:
1 2 3 4 5 | """ >>> 1 in (1,2,3) Becomes >>> import pdb; pdb.set_trace(); 1 in (1,2,3) """ |
然后可以使用调试器签出doctest环境。您不能真正地单步执行doctest,因为每一行都是自动运行的,但是它是调试doctest全局和环境的一个很好的工具。
一些具有reduce和operator的酷特性。
1 2 3 4 5 6 7 8 9 10 11 | >>> from operator import add,mul >>> reduce(add,[1,2,3,4]) 10 >>> reduce(mul,[1,2,3,4]) 24 >>> reduce(add,[[1,2,3,4],[1,2,3,4]]) [1, 2, 3, 4, 1, 2, 3, 4] >>> reduce(add,(1,2,3,4)) 10 >>> reduce(mul,(1,2,3,4)) 24 |
您可以根据需要构建一个函数Kwargs:
1 2 3 | kwargs = {} kwargs[str("%s__icontains" % field)] = some_value some_function(**kwargs) |
str()调用在某种程度上是必需的,因为python会抱怨它不是字符串。不知道为什么;)我将其用于Djangos对象模型中的动态过滤器:
1 | result = model_class.objects.filter(**kwargs) |
命令.getoutput
如果你想得到直接输出到
1 2 3 4 | >>> print commands.getoutput('ls') myFile1.txt myFile2.txt myFile3.txt myFile4.txt myFile5.txt myFile6.txt myFile7.txt myFile8.txt myFile9.txt myFile10.txt myFile11.txt myFile12.txt myFile13.txt myFile14.txt module.py |
将一个字符串相乘以使其重复
1 | print"SO"*5 |
给予
1 | SOSOSOSOSO |
以下是调试类型错误时使用的一个有用函数
1 2 | def typePrint(object): print(str(object) +" - (" + str(type(object)) +")") |
例如,它只打印输入,然后打印类型
1 2 3 | >>> a = 101 >>> typePrint(a) 101 - (<type 'int'>) |
1 2 | for line in open('foo'): print(line) |
这相当于(但更好的)以下内容:
1 2 3 4 | f = open('foo', 'r') for line in f.readlines(): print(line) f.close() |
1 | is_ok() and"Yes" or"No" |
要激活接受它的IDE中的自动完成功能(如idle、editra、iep),而不是:"嗨"。(然后点击标签),你可以在IDE中作弊,只需嗨!(还有你的heat tab)(如你所见,开头没有单引号)因为它只会使用最新的标点符号,就像你添加时一样:点击enter,它会直接添加一个缩进,不知道它是否会更改,但它不再是提示。)
支撑
1 2 3 4 5 6 7 8 9 | def g(): print 'hi!' def f(): ( g() ) >>> f() hi! |