作者:manjusaka
原文链接:http://manjusaka.itscoder.com/2016/11/18/Someone-tell-me-that-you-think-Python-is-simple/
前言
最近觉得 Python 太"简单了",于是在师父川爷面前放肆了一把:"我觉得 Python 是世界上最简单的语言!"。于是川爷嘴角闪过了一丝轻蔑的微笑(内心 OS:Naive,作为一个 Python 开发者,我必须要给你一点人生经验,不然你不知道天高地厚!)于是川爷给我了一份满分 100 分的题,然后这篇文章就是记录下做这套题所踩过的坑。
1.列表生成器
描述
下面的代码会报错,为什么?
class A(object):
x = 1
gen = (x for _ in xrange(10)) # gen=(x for _ in range(10))
if __name__ == "__main__":
print(list(A.gen))
答案
这个问题是变量作用域问题,在gen=(xfor_inxrange(10))中gen是一个generator,在generator中变量有自己的一套作用域,与其余作用域空间相互隔离。因此,将会出现这样的NameError:name' x 'isnotdefined的问题,那么解决方案是什么呢?答案是:用 lambda 。
class A(object):
x = 1
gen = (lambda x: (x for _ in xrange(10)))(
x) # gen=(x for _ in range(10))
if __name__ == "__main__":
print(list(A.gen))
或者这样
class A(object):
x = 1
gen = (A.x for _ in xrange(10)) # gen=(x for _ in range(10))
if __name__ == "__main__":
print(list(A.gen))
补充
感谢评论区几位提出的意见,这里我给一份官方文档的说明吧:
The scope of names defined in a class block is limited to the class block ; it does not extend to the code blocks of methods - this includes comprehensions and generator expressions since they are implemented using a function scope. This means that the following will fail :
class A:
a = 42
b = list(a i for i in range(10))
参考链接Python 2 Execution-Model:Naming-and-Binding,Python 3 Execution-Model:Resolution-of-Names。据说这是 PEP 227 中新增的提案,我回去会进一步详细考证。再次拜谢评论区 @没头脑很着急 @涂伟忠 @ Cholerae 三位的勘误指正。
2.装饰器
描述
我想写一个类装饰器用来度量函数/方法运行时间
import time
class Timeit(object):
def __init__(self, func):
self._wrapped = func
def __call__(self, *args, **kws):
start_time = time.time()
result = self._wrapped(*args, **kws)
print("elapsed time is %s " % (time.time() - start_time))
return result
这个装饰器能够运行在普通函数上:
@Timeit
def func():
time.sleep(1)
return "invoking function func"
if __name__ == '__main__':
func() # output: elapsed time is 1.00044410133
但是运行在方法上会报错,为什么?
class A(object):
@Timeit
def func(self):
time.sleep(1)
return 'invoking method func'
if __name__ == '__main__':
a = A()
a.func() # Boom!
如果我坚持使用类装饰器,应该如何修改?
答案
使用类装饰器后,在调用func函数的过程中其对应的 instance 并不会传递给__call__方法,造成其mehtod unbound,那么解决方法是什么呢?描述符赛高
class Timeit(object):
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|