Декоратор свойств Python не работает должным образом - PullRequest
4 голосов
/ 01 апреля 2012
class Silly:
    @property
    def silly(self):
        "This is a silly property"
        print("You are getting silly")
        return self._silly

    @silly.setter
    def silly(self, value):
        print("You are making silly {}".format(value))
        self._silly = value

    @silly.deleter
    def silly(self):
        print("Whoah, you killed silly!")
        del self._silly

s = Silly()
s.silly = "funny"
value = s.silly
del s.silly

Но это не печатает "Вы становитесь глупыми", "Вы делаете глупые смешные", ... как и ожидалось. Не знаю почему. Можете ли вы сделать, чтобы я выяснил, ребята?

Заранее спасибо!

Ответы [ 2 ]

15 голосов
/ 01 апреля 2012

Декоратор property работает только с классами нового стиля ( см. Также ). Сделайте Silly явным образом расширенным от object, чтобы сделать его классом нового стиля. (В Python 3 все классы являются классами нового стиля)

class Silly(object):
    @property
    def silly(self):
        # ...
    # ...
0 голосов
/ 21 ноября 2015

Как вы, скорее всего, знаете, правильный метод для добавления свойств будет использовать:

@property
def silly(self):
    return self._silly


@silly.setter:
def silly(self, value):
    self._silly = value

Но для этого нужны новые классы стилей, то есть где-то в цепочке должен бытьclass ParentClass(object):.Аналогичная опция использования silly = property(get_silly, set_silly) имеет такое же требование.

Однако существует другая опция, которая заключается в использовании соответствующей закрытой переменной, такой как self._silly, и переопределении __getattr__ и __setattr__ методы:

def __getattr__(self, name): 
    """Called _after_ looking in the normal places for name."""  

    if name == 'silly':
        self._silly
    else:
        raise AttributeError(name)


def __setattr__(self, name, value):
    """Called _before_ looking in the normal places for name."""
    if name == 'silly':
        self.__dict__['_silly'] = value
    else:
        self.__dict__[name] = value

Обратите внимание, как __getattr__ будет вызываться после проверки других атрибутов, но что __setattr__ вызывается до проверки других атрибутов,Поэтому первый может и должен вызвать ошибку, если не принятый атрибут, а второй должен установить атрибут. не используйте self._silly = value в __setattr__, так как это приведет к бесконечной рекурсии.

Также обратите внимание, что, поскольку здесь мы имеем дело со старыми классами стилей, вам следует использовать метод dictи не новее baseclass.__setattr__(self, attr, value), см. документы .Аналогичный __delattr__() также существует, если вы этого хотите.

Используя этот код, вы теперь можете делать такие вещи, как:

i_am = Silly()
i_am.silly = 'No, I'm clever'
print i_am.silly
...