正文
()
a
.
func
()
# Boom!
如果我坚持使用类装饰器,应该如何修改?
答案
使用类装饰器后,在调用
func
函数的过程中其对应的 instance 并不会传递给
__call__
方法,造成其
mehtod unbound
,那么解决方法是什么呢?描述符赛高
class Timeit(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('invoking Timer')
def __get__(self, instance, owner):
return lambda *args, **kwargs: self.func(instance, *args, **kwargs)
3. Python 调用机制
描述
我们知道
__call__
方法可以用来重载圆括号调用,好的,以为问题就这么简单? Naive !
class A(object):
def __call__(self):
print("invoking __call__ from A!")
if __name__ == "__main__":
a = A()
a() # output: invoking __call__ from A
现在我们可以看到
a
()
似乎等价于
a
.
__call__
()
,看起来很 Easy 对吧,好的,我现在想作死,又写出了如下的代码,
a.__call__ = lambda: "invoking __call__ from lambda"
a.__call__()
# output:invoking __call__ from lambda
a()
# output:invoking __call__ from A!
请大佬们解释下,为什么
a
()
没有调用出
a
.
__call__
()
(此题由 USTC 王子博前辈提出 )
答案
原因在于,在 Python 中,新式类( new class )的内建特殊方法,和实例的属性字典是相互隔离的,具体可以看看 Python 官方文档对于这一情况的说明
For new - style classes , implicit invocations of special methods are only guaranteed to work correctly if defined on an object ' s type , not in the object ' s instance dictionary. That behaviour is the reason why the following code raises an exception ( unlike the equivalent example with old - style classes ):
同时官方也给出了一个例子:
class C(object):
pass
c = C()
c.__len__ = lambda: 5
len(c)
# Traceback (most recent call last):
# File "", line 1, in
# TypeError: object of type 'C' has no len()
回到我们的例子上来,当我们在执行
a
.
__call__
=
lambda
:
" invoking __call__ from lambda "
时,的确在我们在
a
.
__dict__
中新增加了一个 key 为
__call__
的 item ,但是当我们执行
a
()
时,因为涉及特殊方法的调用,因此我们的调用过程不会从
a
.
__dict__
中寻找属性,而是从
tyee
(
a
).
__dict__
中寻找属性。因此,就会出现如上所述的情况。
4.描述符
描述
我想写一个 Exam 类,其属性 math 为 [ 0,100 ] 的整数,若赋值时不在此范围内则抛出异常,我决定用描述符来实现这个需求。
class Grade(object):
def __init__(self):
self._score = 0
def __get__(self, instance, owner):
return self._score
def __set__(self, instance, value):
if 0 <= value <= 100:
self._score = value
else:
raise ValueError('grade must be between 0 and 100')
class Exam(object):
math = Grade()
def __init__(self, math):
self