【问题标题】:Difference between @classmethod and a method in python [duplicate]@classmethod和python中的方法之间的区别[重复]
【发布时间】:2013-07-31 08:27:53
【问题描述】:

@classmethod 和 python 中的“经典”方法有什么区别,

什么时候应该使用@classmethod,什么时候应该在python中使用“经典”方法。 classmethod 是否必须是引用类的方法(我的意思是它只是处理类的方法)?

我知道@staticmethod 和经典方法有什么区别 谢谢

【问题讨论】:

  • 没有其实我知道静态方法和方法的区别,我想知道什么时候使用@classmethod,什么时候在我的类中使用函数,这些方法有什么区别
  • 接下来说说方法@classmethod.
  • 它解释了什么是classmethod,而不是classmethod和method之间的区别以及我们何时应该使用@classmethod(带有cls)而不是method(带有self参数)

标签: python


【解决方案1】:

假设您有一个类 Car,它代表系统中的 Car 实体。

classmethod 是一种适用于 Car 类的方法,不适用于 Car 的任何一个实例。因此,用@classmethod 修饰的函数(通常称为cls)的第一个参数就是类本身。示例:

class Car(object):    
    colour = 'red'

    @classmethod
    def blue_cars(cls):
        # cls is the Car class
        # return all blue cars by looping over cls instances

函数作用于类的特定实例;通常称为self 的第一个参数是实例本身:

def get_colour(self):
    return self.colour

总结一下:

  1. 使用classmethod 实现适用于整个类(而不是特定类实例)的方法:

    Car.blue_cars()
    
  2. 使用实例方法来实现适用于特定实例的方法:

    my_car = Car(colour='red')
    my_car.get_colour() # should return 'red'
    

【讨论】:

    【解决方案2】:

    @classmethod 将类作为第一个参数,而函数将类作为实例

    >>> class Test(object):
    ...     def func(self):
    ...         print self
    ...     @classmethod
    ...     def meth(self):
    ...         print self
    
    >>> t = Test()
    >>> t.func()
    <__main__.Test object at 0x00000000027238D0>
    >>> t.meth()
    <class '__main__.Test'>
    

    我故意在meth 中使用了self 参数,因此它在语法上与func 非常接近。但通常你最好使用cls 作为参数:

    ...     @classmethod
    ...     def meth(cls):
    ...         print cls
    

    【讨论】:

    • 最好不要把它命名为self,而是cls
    • 谢谢,我知道,我使用self 只是为了避免混淆,并且方法和函数声明尽可能靠近
    【解决方案3】:

    如果你在一个类中定义一个方法,它会以一种特殊的方式被处理:对它的访问会将它包装在一个特殊的对象中,该对象会修改调用参数以包含self,对被引用对象的引用:

    class A(object):
        def f(self):
            pass
    
    a = A()
    a.f()
    

    这个对a.f 的调用实际上要求f(通过descriptorprotocol)真正返回一个对象。然后这个对象被不带参数调用,并将调用转向真正的f,在前面添加a

    所以a.f() 真正做的是将(a) 作为参数调用原始f 函数。

    为了防止这种情况,我们可以包装函数

    1. 使用 @staticmethod 装饰器,
    2. 带有@classmethod 装饰器,
    3. 与其他一位工作类似的自制装饰师。

    @staticmethod 将其转换为一个对象,当被询问时,该对象会更改参数传递行为,以便它与调用原始f 的意图相匹配:

    class A(object):
        def method(self):
            pass
        @staticmethod
        def stmethod():
            pass
        @classmethod
        def clmethod(cls):
            pass
    
    a = A()
    a.method() # the "function inside" gets told about a
    A.method() # doesn't work because there is no reference to the needed object
    a.clmethod() # the "function inside" gets told about a's class, A
    A.clmethod() # works as well, because we only need the classgets told about a's class, A
    a.stmethod() # the "function inside" gets told nothing about anything
    A.stmethod() # works as well
    

    所以@classmethod@staticmethod 的共同点是它们“不关心”调用它们的具体对象;区别在于@staticmethod 根本不想知道它的任何内容,而@classmethod 想知道它的类。

    所以后者获得了使用的对象是一个实例的类对象。在这种情况下,只需将self 替换为cls

    现在,什么时候用什么?

    嗯,这很容易处理:

    • 如果您有权访问self,您显然需要一个实例方法。
    • 如果您不访问self,但想了解其类,请使用@classmethod。例如,工厂方法可能就是这种情况。 datetime.datetime.now() 就是这样一个例子:你可以通过它的类或实例调用它,但它会创建一个具有完全不同数据的新实例。我什至用它们来自动生成给定类的子类。
    • 如果您既不需要self 也不需要cls,则使用@staticmethod。这也可以用于工厂方法,如果它们不需要关心子类化。

    【讨论】:

    • A @classmethod 接受第一个参数,即类。
    • @MartijnPieters 你是对的,我对此感到困惑。
    • 但现在你的回答只涉及staticmethod,而不是classmethod...
    • @nneonneo 这就是 OP 最初的意思;我现在添加了一个关于@classmethod 的简短部分。
    • 关于@staticmethod 不是@classmethod 的答案是错误,因为@staticmethod 的意义在于您可以调用A.f() 而无需创建实例第一。
    猜你喜欢
    • 1970-01-01
    • 2010-10-30
    • 1970-01-01
    • 2018-09-26
    • 1970-01-01
    • 2016-09-02
    • 2022-01-14
    • 2012-04-02
    • 2015-07-26
    相关资源
    最近更新 更多