2016-11-14 5 views
1

Существует отвеченный вопрос о classmethod и property объединены вместе: Using property() on classmethodsЧто делает classmethod, кроме смены self на cls?

Я до сих пор не понимаю причину этой проблемы, пожалуйста, помогите.

Я понимаю, что он просто заменяет self на cls. Имея это в виду, я написал несколько классных методов в течение последних нескольких лет, и теперь я вижу, что я был не так все время.

И в чем разница между @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 

inc3 с cm работ, но inc1 с classmethod не делает.

ответ

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) 

Для комбинации classmethod и имущества, это может быть сделано путем возвращать пользовательский объект. 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 

[Редактировать]

Q. Что Метод класса() вызов сделать с помощью метода он декорирует для достижения этой цели?

Реализация может быть сделано с помощью 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 

Q.Почему результат не может быть вызван?

Поскольку реализация ClassMethodDescriptor не определяет функцию __call__. После использования @property он вернет ClassMethodDescriptor, который не может быть вызван.

+0

Вы написали, что classmethods не нужен экземпляр. Что вызывает вызов classmethod() с методом, который он украшает для достижения этого? Почему результат не может быть вызван? – VPfB

+0

Я обновил свой ответ. Надеюсь, это будет полезно для вас. –

+0

Спасибо, теперь понятно. '@ classmethod' преобразует функцию в дескриптор. Вызов этих дескрипторов возвращает вызываемую функцию. Последний недостающий элемент - это то, почему он был разработан таким образом. Я могу только догадываться, что главная причина заключается в том, что «детали вызова зависят от того, является ли obj объектом или классом.» (Source: Descriptor HowTo Guide на docs.python.org). Это позволяет различать эти два случая и, таким образом, предоставлять в качестве первого аргумента правые '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 

Также, как вы можете видеть, вам не нужен экземпляр для вызова класса.

+0

Вы показали, что classmethods разные, потому что им не нужен экземпляр. Что вызывает вызов classmethod() с методом, который он украшает для достижения этого? Почему результат не может быть вызван? – VPfB

0

Разница заключается в том, что метод class не может быть вызван, и метод cm может быть вызван. Это означает, что когда свойство (класс) делает вызов введенного func (который он должен делать), он работает так же, как вы, за исключением cm, но не будет работать для classmethod, так как classmethod не имеет звонок реализованы.