提问者:小点点

定义同名的类方法和实例方法


在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定义似乎覆盖了第一个定义。


共1个答案

匿名用户

你不能按你提议的方式去做,但这是可能的。 让我们看看名称空间和装饰器是如何工作的,以了解其中的原因。

语法@ClassMethod是调用装饰器函数ClassMethod并将结果存储在与被装饰对象相同的名称下的简写。 以下是句法糖:

def f (cls):
    print("Cls")

f = classmethod(f)

名称空间,包括类名称空间,基本上是字典。 这意味着您可以将一个对象分配给一个给定的名称。 您可以任意多次重新分配名称,这就是您的代码正在做的事情:

  1. 将函数F分配为实例方法。
  2. 创建另一个函数并将其分配给F
  3. 修饰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"