Возвращаемые свойства класса VS напрямую вызывают свойства [duplicate]

У меня была и эта проблема с некоторыми темами курсора и изменилась на значение по умолчанию, и она сработала. Но я хотел использовать более стильную тему курсора, и на самом деле я использую тот, который отлично работает, больше не происходит сбоев и действительно хороший дизайн:

Нажмите здесь, чтобы посмотреть, как это выглядит (курсор «La Capitaine» тема)

Этапы установки:

1) Copy git repository    
git clone https://github.com/keeferrourke/capitaine-cursors.git

2) Change to the copied directory from git
cd capitaine-cursors

3) Create directory to allocate the cursor theme
sudo mkdir /usr/share/icons/capitaine-cursors

4) Copy the content of bin/xcursor into the created directory
sudo cp -pr bin/xcursor /usr/share/icons/capitaine-cursors
191
задан 13 April 2010 в 09:41

6 ответов

Что такое питонический способ использования геттеров и сеттеров?

Путь «Pythonic» заключается не в использовании «getters» и «seters», а в использовании простых атрибутов, например, на примере, и del для разыменования (но имена изменены для защиты невинные ... builtins):

value = 'something'

obj.attribute = value  
value = obj.attribute
del obj.attribute

Если позже вы хотите изменить настройку и получение, вы можете сделать это, не изменяя код пользователя, используя декоратор property:

class Obj:
    """property demo"""
    #
    @property
    def attribute(self): # implements the get - this name is *the* name
        return self._attribute
    #
    @attribute.setter
    def attribute(self, value): # name must be the same
        self._attribute = value
    #
    @attribute.deleter
    def attribute(self): # again, name must be the same
        del self._attribute

(Каждый декоратор копирует и обновляет предыдущий объект свойства, поэтому обратите внимание, что вы, вероятно, должны использовать одно и то же имя для каждого набора, get и delete function / method.)

After определяя вышеизложенное, исходная настройка, получение и удаление одинаковы:

obj = Obj()
obj.attribute = value  
the_value = obj.attribute
del obj.attribute

Вы должны избегать этого:

def set_property(property,value):  
def get_property(property):  

Во-первых, вышесказанное не работает, потому что вы не предоставляете аргумент для экземпляра, для которого было бы установлено свойство (обычно self), которое было бы:

class Obj:

    def set_property(self, property, value): # don't do this
        ...
    def get_property(self, property):        # don't do this either
        ...

Во-вторых, это дублирует цель двух специальных методов: __setattr__ и __getattr__.

В-третьих, мы также имеем setattr и getattr встроенные функции.

    setattr(object, 'property_name', value)
    getattr(object, 'property_name', default_value)  # default is optional

Декоратор @property предназначен для создания геттеров и сеттеров.

Например, мы могли бы изменить поведение установки, чтобы установить ограничения на устанавливаемое значение: [ ! d13]

    class Protective(object):

        @property
        def protected_value(self):
            return self._protected_value

        @protected_value.setter
        def protected_value(self, value):
            if acceptable(value): # e.g. type or range check
                self._protected_value = value

В общем, мы хотим избежать использования property и просто использовать прямые атрибуты.

Это то, что ожидается от пользователей Python. Следуя правилу наименьшего удивления, вы должны попытаться дать своим пользователям то, что они ожидают, если у вас нет очень веских оснований для обратного.

Демонстрация

Например, скажем, нам нужно наш атрибут защиты объекта должен быть целым числом от 0 до 100 включительно и предотвратить его удаление, с соответствующими сообщениями, чтобы информировать пользователя о его правильном использовании:

class Protective(object):
    def __init__(self, start_protected_value=0):
        self.protected_value = start_protected_value
    @property
    def protected_value(self):
        return self._protected_value
    @protected_value.setter
    def protected_value(self, value):
        if value != int(value):
            raise TypeError("protected_value must be an integer")
        if 0 <= value <= 100:
            self._protected_value = int(value)
        else:
            raise ValueError("protected_value must be " +
                             "between 0 and 100 inclusive")
    @protected_value.deleter
    def protected_value(self):
        raise AttributeError("do not delete, protected_value can be set to 0")

И использование:

>>> p1 = Protective(3)
>>> p1.protected_value
3
>>> p1 = Protective(5.0)
>>> p1.protected_value
5
>>> p2 = Protective(-5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
  File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> p1.protected_value = 7.3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 17, in protected_value
TypeError: protected_value must be an integer
>>> p1.protected_value = 101
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> del p1.protected_value
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 18, in protected_value
AttributeError: do not delete, protected_value can be set to 0

Имеются ли названия?

Да, они не . .setter и .deleter делают копии исходного свойства. Это позволяет подклассам правильно изменять поведение, не изменяя поведение родителя.

class Obj:
    """property demo"""
    #
    @property
    def get_only(self):
        return self._attribute
    #
    @get_only.setter
    def get_or_set(self, value):
        self._attribute = value
    #
    @get_or_set.deleter
    def get_set_or_delete(self):
        del self._attribute

Теперь для этого вам нужно использовать соответствующие имена:

obj = Obj()
# obj.get_only = 'value' # would error
obj.get_or_set = 'value'  
obj.get_set_or_delete = 'new value'
the_value = obj.get_only
del obj.get_set_or_delete
# del obj.get_or_set # would error

I «Не знаю, где это было бы полезно, но прецедент - это если вы хотите получить свойство get, set и / или delete-only. Вероятно, лучше всего придерживаться семантически одного и того же свойства с тем же именем.

Заключение

Начать с простых атрибутов.

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

Избегайте функций с именем set_... и get_... - вот для чего нужны свойства.

92
ответ дан 15 August 2018 в 16:18
  • 1
    Помимо дублирования доступных функций, почему следует избегать написания собственных настроек и геттеров? Я понимаю, что это может быть не путинский путь, но есть ли действительно серьезные проблемы, с которыми можно столкнуться в противном случае? – user1350191 27 July 2018 в 16:56
  • 2
    @ user1350191 Я на работе, я вернусь к этому чуть позже и расширю свой ответ - и я дам вам знать, когда я это сделаю. – Aaron Hall♦ 27 July 2018 в 17:20
  • 3
    В вашей демонстрации метод __init__ относится к self.protected_value, но получатели и сеттеры относятся к self._protected_value. Не могли бы вы объяснить, как это работает? Я тестировал ваш код, и он работает так, как есть - так что это не опечатка. – codeforester 28 July 2018 в 03:36
  • 4
    @codeforester Я надеялся ответить в своем ответе раньше, но пока не могу, этого комментария должно хватить. Надеюсь, вы увидите, что он использует свойство через public api, гарантируя, что он «защищен». Было бы нецелесообразно «защищать». он с свойством, а затем использовать непубличный api вместо __init__, не так ли? – Aaron Hall♦ 1 August 2018 в 22:37
  • 5
    Да, @AaronHall получил его сейчас. Я не понял, что self.protected_value = start_protected_value на самом деле вызывает функцию setter; Я думал, что это задание. – codeforester 1 August 2018 в 23:42
[F1]
20
ответ дан 15 August 2018 в 16:18

Использование @property и @ attribute.setter помогает не только использовать «питонический» способ, но и проверять правильность атрибутов при создании объекта и при его изменении.

class Person(object):
    def __init__(self, p_name=None):
        self.name = p_name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, new_name):
        if type(new_name) == str: #type checking for name property
            self._name = new_name
        else:
            raise Exception("Invalid value for name")

Таким образом, вы фактически скрываете атрибут _name от разработчиков-клиентов, а также выполняете проверки типа свойства имени. Обратите внимание, что, следуя этому подходу даже во время инициализации, вызывающий сеттер. Итак:

p = Person(12)

приведет к:

Exception: Invalid value for name

Но:

>>>p = person('Mike')
>>>print(p.name)
Mike
>>>p.name = 'George'
>>>print(p.name)
George
>>>p.name = 2.3 # Causes an exception
0
ответ дан 15 August 2018 в 16:18

Попробуйте следующее: Свойство Python

Пример кода:

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

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

    @x.setter
    def x(self, value):
        print("setter of x called")
        self._x = value

    @x.deleter
    def x(self):
        print("deleter of x called")
        del self._x


c = C()
c.x = 'foo'  # setter called
foo = c.x    # getter called
del c.x      # deleter called
515
ответ дан 15 August 2018 в 16:18
  • 1
    Пример использования будет очень оценен. – Clever Programmer 18 November 2015 в 16:36
  • 2
    Как называются эти геттеры и сеттеры? – Alex Spurling 15 September 2017 в 19:52
  • 3
    @AaronHall, поэтому, когда вы моделируете вещи в python. Что такое питонический путь? Как и в java, у вас есть все эти getters / setters, equals, hascode templateplate. Это просто не происходит в python? Как выглядит типичный класс в модели? Просто init? – WhitneyChia 13 August 2018 в 19:01
  • 4
    @WhitneyChia Вы могли бы поговорить об этом в чате python: chat.stackoverflow.com/rooms/6/python - но комментарии - это не место для обсуждения ... Проще говоря, там нет "типичного класса" в Python, потому что дизайн должен вытекать из требований - я бы согласился с тем, что __init__, вероятно, является наиболее распространенным специальным методом, но даже это не требуется. Если вы ищете хорошие примеры, проверьте код Python в стандартной библиотеке: github.com/python/cpython/tree/master/Lib – Aaron Hall♦ 13 August 2018 в 19:17

Примечание: свойство, вероятно, лучший способ сделать это, посмотрите на другие ответы

Определите __setattr__(self, name, value) и / или __getattr__(self, name): obj.abc -> type(obj).__getattr__(obj, 'abc')

-4
ответ дан 15 August 2018 в 16:18
  • 1
    Можете ли вы представить более подробный пример кода? – Steven Vascellaro 31 January 2018 в 21:29

Проверьте декоратор @property.

16
ответ дан 15 August 2018 в 16:18

Другие вопросы по тегам:

Похожие вопросы: