Как Python со встроенной @property получает перегруженную функцию сеттера? - PullRequest
0 голосов
/ 02 октября 2018

При определении встроенного свойства python с помощью @property, как объект свойства отличает установщик от метода получателя, при условии, что они перегружены (имеют одно и то же имя)?

class A:

    def __init__(self):
        self._x = 12

    @property
    def x(self) -> int:
        return self._x

    @notifiable # strangely this stacks on both setter and getter
    @x.setter
    def x(self, val: int):
        self._x = val

Если яопределить собственный декоратор свойств, скажем:

class my_property:
    def __init__(self, getter):
        print("__init__ getter %s:" % getter)

    def setter(self, setter: FunctionType):
        print("setter: %s" % setter)


class B:
    def __init__(self):
        self._val = 44

    @my_property
    def x(self):
        return self._val

    @x.setter
    def x(self, val):
        self._val = val

Выполнение кода приводит к следующему выводу

__init__ getter <function B.x at 0x7ff80c5e1620>:
setter: <function B.x at 0x7ff80c5e1620>

Функции getter и setter, передаваемые декоратору, являются одной и той же функцией,но они должны быть разными функциями.

Если я использую аннотацию, подобную этой:

class C:
    def __init__(self):
        self._val = 44

    @my_property
    def x(self):
        return self._val

    @x.setter
    def set_x(self, val):
        self._val = val

Как и ожидалось, печатается другая функция.

__init__ getter <function C.x at 0x7f529132c6a8>:
setter: <function C.set_x at 0x7f529132c6a8>

КакPython решает эту проблему с помощью встроенного @property?Относится ли декоратор к пользовательским декораторам?

1 Ответ

0 голосов
/ 02 октября 2018

Причина, по которой вы видите то, что вы видите здесь, в том, что вы нигде не храните ссылку на геттер.Это означает, что после завершения метода __init__ ссылка на первый Bx больше не будет (т. Е. Refcount равен нулю), поэтому функция будет освобождена.Поскольку исходная функция получения была выпущена, Python может повторно использовать тот же адрес памяти для другого объекта / функции, что и происходит в этом случае.

Если вы измените my_property, чтобы сохранить ссылку на оригиналметод getter как таковой:

class my_property:
    def __init__(self, getter):
        print("__init__ getter %s:" % getter)
        self.getter = getter

    def setter(self, setter: FunctionType):
        print("setter: %s" % setter)

вы увидите, что имя функции (Bx) остается прежним (что нормально, так как python не использует имя функции для уникальной идентификации функции),однако адрес памяти двух функций различен:

__init__ getter <function B.x at 0x7f9870d60048>
setter: <function B.x at 0x7f9870d600d0>

Обрабатывается ли декоратор иначе, чем пользовательские декораторы?

Нет, свойство просто обычный декоратор.Однако, если вы хотите переопределить декоратор свойств, вам, вероятно, будет интересен протокол дескриптора (на этой странице чисто переопределение @property на python).

...