在python中,有没有可能定义一个实例方法和一个类方法具有相同的名称?
示例:
class C:
def f (self):
print("Inst")
@classmethod
def f (cls):
print("Cls")
c = C()
c.f() #This should print "Inst"
C.f() #This should print "Cls"
在示例代码中,ClassMethod
定义似乎覆盖了第一个定义。
你不能按你提议的方式去做,但这是可能的。 让我们看看名称空间和装饰器是如何工作的,以了解其中的原因。
语法@ClassMethod
是调用装饰器函数ClassMethod
并将结果存储在与被装饰对象相同的名称下的简写。 以下是句法糖:
def f (cls):
print("Cls")
f = classmethod(f)
名称空间,包括类名称空间,基本上是字典。 这意味着您可以将一个对象分配给一个给定的名称。 您可以任意多次重新分配名称,这就是您的代码正在做的事情:
F
分配为实例方法。F
。F
,并将其分配回与上面所示相同的名称。所有这三个操作都将覆盖前一个操作的结果。
变通方法
但是,类和实例具有单独的命名空间。 没有什么可以阻止您将不同的对象分配给每个对象中的f
,但您必须小心地执行此操作:
class C:
def __init__(self):
def f():
print("Inst")
self.f = f
@classmethod
def f (cls):
print("Cls")
c = C()
c.f() # Prints "Inst"
C.f() # Prints "Cls"
这样做的目的是在类和实例的命名空间中分别分配名称f
。 由于函数是非数据描述符(它们有一个__get_
方法要绑定,但没有一个__set_
方法),因此调用c.f()
将访问c
中的f
,而不是首先查看类。
比较属性,属性是数据描述符。 即使实例中有一个属性f
,当类中有一个名为f
的属性
时,使用简单的点表示法也不可能访问它。
实例“method”本身将不是绑定方法对象。 它将是一个普通函数,但可以通过其封闭的非本地命名空间访问self
。 这对于大多数应用程序来说可能已经足够了。 但是,如果确实需要绑定方法,也可以通过使用不同的名称包装方法并将其分配给实例来实现:
class C:
def __init__(self):
self.f = self._f # This creates a bound method
def _f(self):
print("Inst")
@classmethod
def f (cls):
print("Cls")
c = C()
c.f() # Prints "Inst"
C.f() # Prints "Cls"