首页 文章

@classmethod和python中的方法之间的区别[重复]

提问于
浏览
3

这个问题在这里已有答案:

@classmethod 和python中的'classic'方法有什么区别,

我应该何时使用 @classmethod ,何时应该在python中使用'classic'方法 . classmethod必须是一个被引用给类的方法(我的意思是它只是一个处理类的方法)?

我知道@staticmethod和经典方法Thx之间有什么区别

3 回答

  • 4

    假设您有一个类 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
    

    总结一下:

    • 使用 classmethod 来实现适用于整个类(而不是特定类实例)的方法:
    Car.blue_cars()
    
    • 使用实例方法来实现在特定实例上工作的方法:
    my_car = Car(colour='red')
    my_car.get_colour() # should return 'red'
    
  • 2

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

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

    这次对 a.f 的调用实际上要求 f (通过descriptor protocol)对象真正返回 . 然后在没有参数的情况下调用此对象,并将调用偏转到实际 f ,在前面添加 a .

    那么 a.f() 真正做的是用 (a) 作为参数调用原始的 f 函数 .

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

    带有 @staticmethod 装饰的


    • 带有 @classmethod 装饰的

    • 与其他一个类似的工作,自制装饰器 .

    @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 . 如果他们不需要关心子类化,这也可以用于工厂方法 .

  • 5

    @classmethod 将类作为第一个参数,而function接受类的实例

    >>> 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
    

相关问题