|
你想要扩展函数中的某个闭包,允许它能访问和修改函数的内部变量。
解决方案
通常,闭包的内部变量对外界是完全隐藏的。但可以编写访问函数,将其作为函数属性绑定到闭包上来实现访问。- def sample():
- n = 0
- # 闭包函数
- def func():
- print('n=', n)
- # 属性n的访问方法
- def get_n():
- return n
- def set_n(value):
- nonlocal n
- n = value
- # 附加为函数属性
- func.get_n = get_n # 将get_n函数附加为func函数的属性
- func.set_n = set_n
- return func
- f = sample()
- f()
- f.set_n(10)
- f()
- f.get_n()
- f()
复制代码 输出:注意两点:
- nonlocal 声明可以让我们编写函数来修改内部变量的值。
- 函数属性允许将访问方法绑定到闭包函数上。
讨论
闭包模拟类的实例。仅仅是复制上面的内部函数到一个字典并返回。- import sys
- class ClosureInstance:
- def __init__(self, locals=None):
- if locals is None:
- locals = sys._getframe(1).f_locals
- # 使用可调用对象更新字典
- self.__dict__.update((key,value) for key, value in locals.items()
- if callable(value) )
- # 重定向的特殊方法
- def __len__(self):
- return self.__dict__['__len__']()
- def Stack():
- items = []
- def push(item):
- items.append(item)
- def pop():
- return items.pop()
- def __len__():
- return len(items)
- return ClosureInstance()
- s = Stack()
- print(s)
- s.push(10)
- s.push(20)
- s.push('hello')
- print(len(s))
复制代码 输出:- <__main__.ClosureInstance object at 0x00000189D3A55F88>
- 3
复制代码 这个代码比普通的类定义要快很多。- class Stack2: def __init__(self): self.items = [] def push(self, item): self.items.append(item) def pop(self): return self.items.pop() def __len__(self): return len(self.items)#学习中遇到问题没人解答?小编创建了一个Python学习交流群:15<__main__.ClosureInstance object at 0x00000189D3A55F88>
- 3708845from timeit import timeits = Stack()print(timeit('s.push(1);s.pop()', 'from __main__ import s'))s2 = Stack2()print(timeit('s2.push(1);s2.pop()', 'from __main__ import s2'))
复制代码 输出:- 0.<__main__.ClosureInstance object at 0x00000189D3A55F88>
- 3<__main__.ClosureInstance object at 0x00000189D3A55F88>
- 3069740.<__main__.ClosureInstance object at 0x00000189D3A55F88>
- 34851409999999994
复制代码 闭包方案运行起来要快 8%,原因是对实例变量的访问,闭包不会涉及到额外的 self 变量。
注意:
在代码的编写中一般不会这样做。原因如下:
虽然它运行更快,但它只是真实类的一个奇怪替换。
此时类的继承、属性、描述器、类方法都不能用。并且要做额外的工作才能让一些特殊方法生效(比如上面ClosureInstance 中重写的 __len__())。
让阅读代码的人感到疑惑,看起来不是一个普通的类定义。
来源:https://www.cnblogs.com/xxpythonxx/p/18191669
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
|