命名空间
globals其实就是一个dict,可以直接添加项
locals()和globals()
在函数外部,locals() 和 globals() 作⽤用完全相同。⽽而当在函数内部调⽤用时,locals() 则是获取当前 函数堆栈帧的名字空间,其中存储的是函数参数、局部变量等信息
引用传递
对象总是按引⽤用传递,简单点说就是通过复制指针来实现多个名字指向同⼀一对象。因为 arena 也是 在堆上分配的,所以⽆无论何种类型何种⼤大⼩小的对象,都存储在堆上。Python 没有值类型和引⽤用类
如果不希望对象被修改,就需使⽤用不可变类型,或对象复制品。 不可变类型:int, long, str, tuple, frozenset
除了某些类型⾃自带的 copy ⽅方法外,还可以: • 使⽤用标准库的 copy 模块进⾏行深度复制。 • 序列化对象,如 pickle、cPickle、marshal
>>> import copy
>>> x = object()
>>> l = [x]! ! ! ! # 创建一个列表。
>>> l2 = copy.copy(l)! ! # 浅复制,仅复制对象自身,而不会递归复制其成员。
>>> l2 is l! ! ! ! # 可以看到复制列表的元素依然是原对象。
False
>>> l2[0] is x
True
>>> l3 = copy.deepcopy(l)!! # 深度复制,会递归复制所有深度成员。
>>> l3 is l! ! ! ! # 列表元素也被复制了。
False
>>> l3[0] is x
False
eval
>>> eval("(1 + 2) * 3")! ! # 假装看不懂这是啥……
9
>>> eval("{'a': 1, 'b': 2}")! # 将字符串转换为 dict。
{'a': 1, 'b': 2}
>>> x = 100
>>> eval("x + 200")!! ! # 使⽤用当前上下文的名字空间。
300
>>> ns = dict(x = 10, y = 20)
>>> eval("x + y", ns)! ! # 使用自定义名字空间。
30
>>> ns.keys()! ! ! # 名字空间里多了 __builtins__。
['y', 'x', '__builtins__']
要执行代码片段,或者 PyCodeObject 对象,那么就需要动用 exec 。同样可以带入自定义名字空
间,以避免对当前环境造成污染。
>>> py = """
... class User(object):
... def __init__(self, name):
... self.name = name
... def __repr__(self):
... return "<User: {0:x}; name={1}>".format(id(self), self.name)
... """
>>> ns = dict()
>>> exec py in ns! ! ! # 执行代码片段,使用自定义的名字空间。
>>> ns.keys()! ! ! # 可以看到名字空间包含了新的类型:User。
['__builtins__', 'User']
>>> ns["User"]("Tom")! ! # 完全可用。貌似用来开发 ORM 会很简单。
<User: 10547f290; name=Tom>
继续看 exec 执行 PyCodeObject 的演示
>>> py = """
... def incr(x):
... global z
... z += x
... """
>>> code = compile(py, "test", "exec")! ! ! # 编译成 PyCodeObject。
>>> ns = dict(z = 100)! ! ! ! ! # ⾃自定义名字空间。
>>> exec code in ns!! ! ! ! ! # exec 执⾏行以后,名字空间多了 incr。
>>> ns.keys()! ! ! ! ! ! # def 的意思是创建⼀一个函数对象。
['__builtins__', 'incr', 'z']
>>> exec "incr(x); print z" in ns, dict(x = 50)! # 试着调⽤用这个 incr,不过这次我们提供⼀一个
150! ! ! ! ! ! ! ! #! local 名字空间,以免污染 global。
>>> ns.keys()! ! ! ! ! ! # 污染没有发⽣生。
['__builtins__', 'incr', 'z']
bool
>>> map(bool, [None, 0, "", u"", list(), tuple(), dict(), set(), frozenset()])
[False, False, False, False, False, False, False, False, False]
精度问题
>>> from decimal import Decimal, ROUND_UP, ROUND_DOWN
>>> float('0.1') * 3 == float('0.3')! ! ! ! ! # float 转型精度不同
False
>>> Decimal('0.1') * 3 == Decimal('0.3')! ! ! ! # decimal 没有问题
True
>>> Decimal('2.675').quantize(Decimal('.01'), ROUND_UP)! ! # 精确控制 round
Decimal('2.68')
>>> Decimal('2.675').quantize(Decimal('.01'), ROUND_DOWN)
Decimal('2.67')
注释使用"""doc""",方便生成帮助信息
>>> def test():
... """
... func help
... """
... pass
>>> test.__doc__
'\n func help\n '
>>> class User(object):
... """User Model"""
...
... def __init__(self):
... """user.__init__"""
... pass
>>> User.__doc__
'User Model'
>>> User.__init__.__doc__
'user.__init__'
while
比我们熟悉的 while 多了个可选的 else 分支。如果循环没有被中断,那么 else 就会执行
>>> x = 3
>>> while x > 0:
... x -= 1
... else:
... print "over!"
over!
>>> while True:
... x += 1
... if x > 3: break
... else:
... print "over!"
Generator
用一种优雅的方式创建列表、字典或集合。
>>> [x for x in range(10)] # 列表
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> {x for x in range(10)} # 集合
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> {c:ord(c) for c in "abc"} # 字典
{'a': 97, 'c': 99, 'b': 98}
>>> (x for x in range(10))
<generator object <genexpr> at 0x10328a690>
可带上条件进⾏行过滤。
>>> [x for x in range(10) if x % 2]
[1, 3, 5, 7, 9]
或⽤用多个 for ⼦子句实现嵌套。
>>> ["{0}{1}".format(c, x) for c in "abc" for x in range(3)]
['a0', 'a1', 'a2', 'b0', 'b1', 'b2', 'c0', 'c1', 'c2']