2016-11-14 22 views
1

有一个回答问题约classmethodproperty结合在一起:Using property() on classmethods除了将自己更改为cls,classmethod会做什么?

我还是不明白这个问题的原因,请大家帮忙。

我对classmethod的理解是,它只是用cls代替self。考虑到这一点,我在过去几年里写了几个classmethods,现在我发现我一直都是错的。

那么@classmethod@cm与下面的代码有什么区别?

def cm(func): 
    def decorated(self, *args, **kwargs): 
     return func(self.__class__, *args, **kwargs) 
    return decorated 

class C: 
    V = 0 

    @property 
    @classmethod 
    def inc1(cls): 
     cls.V += 1 
     print("V1 =", cls.V) 

    @property 
    @cm 
    def inc3(cls): 
     cls.V += 3 
     print("V3 =", cls.V) 

c = C() 
#c.inc1 # fails with: TypeError: 'classmethod' object is not callable 
c.inc3 # works 

inc3cm作品,但inc1classmethod没有。

回答

2

@classmethod和@cm从下面的代码有什么区别?

装饰器在创建实例之前的类创建时调用。

对于您的情况,由于@cm返回func(self.__class__, *args, **kwargs),依赖于self,因此应将其用作实例方法。

另一方面,@classmethod可以在创建实例之前使用。

def cm(func): 
    def decorated(self, *args, **kwargs): 
     return func(self.__class__, *args, **kwargs) 
    return decorated 

class C: 
    @classmethod 
    def inc1(cls): 
     (blablabla) 
    @cm 
    def inc3(cls): 
     (blablabla) 

C().inc1() # works as a instance method 
C.inc1() # works as a classmethod 
C().inc3() # works as a instance method 
C.inc3() # TypeError: unbound method decorated() must be called with C instance as first argument (got nothing instead) 

对于类方法和属性的组合,它可以通过返回一个自定义对象来完成。 Reference

class ClassPropertyDescriptor(object): 
    def __init__(self, f): 
     self.f = f 
    def __get__(self, obj, klass=None): 
     if klass is None: 
      klass = type(obj) 
     return self.f.__get__(obj, klass)() 

def classproperty(func): 
    if not isinstance(func, (classmethod, staticmethod)): 
     func = classmethod(func)  
    return ClassPropertyDescriptor(func) 

class C: 
    @classproperty 
    def inc1(cls): 
     (blablabla) 

C.inc1 # works as a classmethod property 

[编辑]

问:什么是类方法()调用做的方法是装饰来实现呢?

实现可以通过使用descriptor

class ClassMethodDescriptor(object):  
    def __init__(self, f): 
     self.f = f 
    def __get__(self, obj, klass=None): 
     if klass is None: 
      klass = type(obj) 
     def newfunc(*args): 
      return self.f(klass, *args) 
     return newfunc 

def myclassmethod(func): 
    return ClassMethodDescriptor(func) 

class C: 
    @myclassmethod 
    def inc1(cls): 
     (blablabla) 

C.inc1() # works as a classmethod 

问:为什么结果不调用来完成?

因为执行ClassMethodDescriptor没有定义__call__函数。一旦使用@property,它将返回不可调用的ClassMethodDescriptor。

+0

你写过那个classmethods不需要一个实例。 classmethod()调用使用它所实现的方法进行修饰的方法是什么?为什么结果不可调用? – VPfB

+0

我更新了我的答案。希望这会对你有所帮助。 –

+0

谢谢,现在更清楚了。 '@ classmethod'将函数转换为描述符。调用这个描述符返回一个可调用的函数。最后缺失的部分是为什么它是这样设计的。我只能猜测主要原因是“_调用的细节取决于obj是一个对象还是一个class._”(来源:docs.python.org上的Descriptor HowTo指南)。这使得区分这两种情况成为可能,因此提供了正确的“cls”作为第一个参数。正如我所说,只是猜测。 – VPfB

-1

类方法不知道有关实例的任何内容,并且不需要它。 实例方法知道它是实例,它是类。

class Foo: 
    some = 'some' 

class Bar(Foo): 
    def __init__(self): 
     self.some = 'not some' 
    @classmethod 
    def cls_some(cls): 
     print(cls.some) 
    def instance_some(self): 
     print(self.some) 



Bar.cls_some() 
>>>some 
Bar().instance_some() 
>>>not some 

此外,你可以看到你不需要一个实例来调用classmethod。

+0

您已经证明,classmethods是不同的,因为它们不需要实例。 classmethod()调用使用它所实现的方法进行修饰的方法是什么?为什么结果不可调用? – VPfB

0

区别在于classmethod不可调用,cm方法可调用。这意味着当属性(类)调用输入的func(它应该这样做)时,它的工作原理与cm相同,但对classmethod不起作用,因为classmethod没有调用实现。

相关问题