[英]Why a subclass would override a base class method but make it identical (and not use it)?
[英]Why is a method not identical to itself?
运营商
is
和is not
测试对象的身份:x is y
为真,当且仅当x
和y
是同一个对象。x is not y
产生反真值。
让我们尝试一下:
>>> def m():
... pass
...
>>> m is m
True
由于自动进行垃圾回收,释放列表以及描述符的动态性质,您可能会注意到在
is
运算符的某些用法中,看似不寻常的行为,例如涉及实例方法或常量之间比较的行为。 查看他们的文档以获取更多信息。
>>> class C:
... def m():
... pass
...
>>> C.m is C.m
False
我搜索了更多的解释,但找不到任何解释。
为什么Cm is Cm
错误?
我正在使用Python2.x。 如以下答案中所述,在Python 3.x Cm is Cm
为true。
当您要求一个函数实例的属性时,您将获得一个绑定方法 :一个可调用对象,该对象包装了在类中定义的函数,并将实例作为第一个参数传递。 在Python 2.x中,当您请求类的属性(即函数)时,您会得到一个类似的代理对象,称为未绑定方法 :
>>> class A: m = lambda: None
...
>>> A.m
<unbound method A.<lambda>>
这个特殊对象是在您需要时创建的,并且显然没有缓存在任何地方。 那意味着当你做
>>> A.m is A.m
False
您正在创建两个不同的未绑定方法对象,并测试它们的身份。
注意
>>> x = A.m
>>> x is x
True
和
>>> A.m.im_func is A.m.im_func
True
工作正常。 ( im_func
是未绑定方法对象包装的原始函数。)
顺便说一句,在Python 3.x中, Cm is Cm
为True,因为(几乎没有意义的)未绑定方法代理对象已被完全删除,而您只获得了定义的原始函数。
这只是Python中属性查找非常动态的一个示例:当您请求对象的属性时,可以运行任意Python来计算该属性的值。 这是另一个测试失败的示例,其中的原因更加清楚:
>>> class ChangingAttribute(object):
... @property
... def n(self):
... self._n += 1
... return self._n
...
... def __init__(self):
... self._n = 0
...
>>> foo = ChangingAttribute()
>>> foo.n
1
>>> foo.n
2
>>> foo.n
3
>>> foo.n is foo.n
False
>>> foo.n
6
我假设您正在使用Python 2? 在Python 3中, Cm is Cm
(但C().m is C().m
仍为false)。 如果您在REPL上仅输入Cm
,我敢打赌您会看到类似<UnboundMethod... >
。 除了检查isinstance(self, cls)
之外,UnboundMethod包装器几乎没有做。 (似乎没有必要为此创建包装器?是的,因此将其丢弃在Python 3中Cm
只是一个函数)。 每当访问该方法时,都会按需创建一个新的包装实例Cm
创建一个,另一个Cm
创建另一个。 由于它们是不同的实例,因此Cm is not Cm
。
绑定方法密切相关,使您可以执行f = obj.method; f(*args)
f = obj.method; f(*args)
但也会导致instance.method is not instance.method
。 实例化后,该类中定义的所有函数(阅读:所有方法,除了猴子修补的方法外)均成为实例的属性。 当您访问它们时,您将获得围绕纯函数的包装器的新实例(绑定方法)。 该包装器会记住实例( self
),并在使用(arg1, arg2, ..., argN)
进行调用时,将其交给函数-将self
作为第一个参数添加。 您通常不会注意到,因为您立即调用了该方法-但这是允许隐式传递self
而不诉诸于语言级技巧的原因。
因为Cm()不是类C的静态方法,所以:
像这样尝试:
class C:
@staticmethod
def m():
pass
print C.m is C.m
# True
c = C()
print c.m is C.m
# True
因为静态方法就像类变量,所以我们只需要一个引用即可,因此,如果我们更改其绑定值,则该更改应该在该类的所有类和实例中都是自动的。
另一方面,在您的示例中, Cm
不是静态方法,因此Python假定应该将其视为非静态方法,因此无论何时调用Cm
,它都会返回一个新实例:
class C:
def m():
pass
a = C.m
b = C.m
print id(a), id(b)
# 43811616, 43355984
print a is b
# False
注意:静态方法不像类方法!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.