Python – несколько операторов @property в определении класса?

Ускорение обучения на уроках. Я читал, что конструктор (def init в Python) должен устанавливать только назначенные переменные, а вычисляемые атрибуты экземпляра должны устанавливаться через свойство. Кроме того, использование @property предпочтительнее, чем геттер/сеттер в стиле Java.

Хорошо, но каждый пример, который я когда-либо видел, устанавливает только одно свойство. Допустим, у меня есть объект с тремя сложными атрибутами, которые необходимо вычислить, запросить и т. д. Как представить несколько геттеров @property, сеттеров, удалителей? сильный>? Вот пример из другого сообщение:

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

Итак, если бы у меня было три переменных экземпляра, значения которых вычислялись на основе некоторых других атрибутов, выглядело бы это так:

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

    @property
    def y(self):
        """I'm the 'y' property."""
        return self._y

    @y.setter
    def y(self, value):
        self._y = value

    @y.deleter
    def y(self):
        del self._y

    @property
    def z(self):
        """I'm the 'z' property."""
        return self._z

    @z.setter
    def z(self, value):
        self._z = value

    @z.deleter
    def z(self):
        del self._z

Или тот факт, что я вижу только один оператор @property, означает, что иметь класс с более чем одним @property — плохая идея?


person Alan S    schedule 20.02.2014    source источник


Ответы (5)


Нет, вы можете использовать несколько декораторов @property сколько душе угодно. Здесь, видимо, нет предела, кроме фантазии авторов примеров.

Стандартная библиотека Python полна @property использования, если вам нужны примеры:

  • numbers определяет ABC для классов чисел в Python.

  • tempfile реализует временные файловые объекты

  • threading обеспечивает поддержку потоков более высокого уровня.

  • urlparse для обработки URL-адресов и строк запросов.

и Т. Д.

У вас было это на месте; несколько свойств будут выглядеть точно так же, как вы опубликовали.

person Martijn Pieters    schedule 20.02.2014

это не плохая идея. это обычный шаблон свойств.

другой шаблон работает так:

class A(object):

    def _get_a(self):
        return self._a

    def _set_a(self, v)
        self._a = v

    def _del_a(self)
        del self._a

    a = property(_get_a, _set_a, _del_a)

результат тот же, что и в первом примере, и вы можете использовать его сколько угодно. инициализация self._a в конструкторе — хорошая идея, поскольку в противном случае доступ к нему ДО вызова self.a вызовет AttributeError

person Luis Masuelli    schedule 20.02.2014
comment
Рассмотрите возможность использования только myObj.foo или myObj.foo() вместо myObj.set_foo(). Люди расходятся в этом, но все согласны с тем, что get_ в целом бесполезен и просто делает вещи похожими на Java. - person a p; 21.02.2014
comment
Спасибо, я не подумал об инициализации. Так что я бы просто сказал что-то вроде def __init__(self, a=None): self.a = a? - person Alan S; 21.02.2014
comment
да, это было бы то же самое, но более инкапсулированное. - person Luis Masuelli; 21.02.2014
comment
@ap я исправил свой код (добавлено подчеркивание перед удалением и установкой). обратите внимание, что методы защищены, и единственное их предназначение — использовать в качестве аргументов конструктора property(), поэтому они не предназначены для публичного доступа и являются просто примером для иллюстрации. Я предпочитаю шаблон декоратора свойств для геттера, сеттера и удаления. - person Luis Masuelli; 21.02.2014
comment
Проголосовал за демонстрацию более лаконичной формы оформления набора средств доступа к свойствам. Иногда менее вертикальный код улучшает читабельность, особенно если у вас есть однострочные методы доступа, подобные этому, которые могут быть организованы в виде блоков из 4 строк плюс начальный комментарий. - person Rakurai; 25.04.2019

Чтобы подпрыгнуть на другом ответе,

нет короткого пути к несколько уродливому шаблону

На самом деле не в python stdlib, но теперь есть библиотека с именем pyfields, чтобы сделать это в более лаконичным способом, не жертвуя скоростью, когда вам не нужны валидаторы и конвертеры.

from pyfields import field, init_fields

class C(object):
    x = field(default=None, doc="the optional 'x' property")
    y = field(doc="the mandatory 'y' property")
    z = field(doc="the mandatory 'z' property")

    @init_fields
    def __init__(self):
        pass

c = C(y=1, z=2)
print(vars(c))

урожаи

{'z': 2, 'y': 1, 'x': None}

Я автор этой библиотеки, я написал ее, потому что ни одна из существующих альтернатив меня удовлетворили.

Подробнее см. в документации. Не стесняйтесь оставлять отзывы!

person smarie    schedule 11.10.2019

Это может быть некрасиво, но так оно и работает. В общем, pythonic рекомендует не создавать простые установщики/геттеры, которые напрямую обращаются к нативной переменной (если только вы не знаете, что интерфейс может измениться). Предполагая, что причиной свойств являются «сложные вычисления», как вы сказали, нет ярлыка для несколько уродливого шаблона. См. эту ссылку http://tomayko.com/writings/getters-setters-fuxors

person user590028    schedule 20.02.2014

да, но декоратор @property делает определение нескольких свойств в классе более аккуратным и аккуратным. Свойство отличается атрибутом. Свойство Reason используется в инкапсуляции, поскольку в python нет встроенного модификатора доступа. Фактически, когда мы вызываем декоратор @property над методом, мы создаем экземпляр объекта свойства. Объект свойства — это объект, имеющий методы get, set и del. Свойство можно определить в классе без необходимости определять его в init. Метод init вызывается при создании экземпляра объекта. Если частный атрибут необходимо установить при создании объекта, определите его в init, но когда нам не нужно начальное значение, нам не нужно определять атрибуты. Вот пример свойства без атрибута.

class C(object):
#X Property
@property
def x(self):
    """I'm the 'x' property."""
    print('Get The X Property')
    return self._x

@x.setter
def x(self, value):
    print('X Property Setted to {}'.format(value))
    self._x = value

@x.deleter
def x(self):
    print('X is Killed !')
    del self._x

#Y Property
@property
def y(self):
    """I'm the 'y' property."""
    print('Get The Y Property')
    return self._y

@y.setter
def y(self, value):
    print('Y Property Setted to {} '.format(value))
    self._y = value

@y.deleter
def y(self):
    print('Y is Killed !')
    del self._y

Когда нам нужно определить x и y как атрибут класса C. Просто установите атрибут в init. поэтому x и y указаны как атрибут класса C и имеют начальное значение, установленное при создании экземпляра объекта.

class C(object):
def __init__(self):
    self._x = 0
    self._y = 0

#X Property
@property
def x(self):
    """I'm the 'x' property."""
    print('Get The X Property')
    return self._x

@x.setter
def x(self, value):
    print('X Property Setted to {}'.format(value))
    self._x = value

@x.deleter
def x(self):
    print('X is Killed !')
    del self._x

#Y Property
@property
def y(self):
    """I'm the 'y' property."""
    print('Get The Y Property')
    return self._y

@y.setter
def y(self, value):
    print('Y Property Setted to {} '.format(value))
    self._y = value

@y.deleter
def y(self):
    print('Y is Killed !')
    del self._y

Разница проста. Без какого-либо начального значения класс C не имеет атрибутов x и y. поэтому, если мы попытаемся получить атрибут, возникнет исключение. С начальным значением класс C уже имеет атрибуты X и Y с самого начала.

person Willy satrio nugroho    schedule 16.06.2018