Python - Может ли логика одного свойства применяться к нескольким атрибутам? - PullRequest
0 голосов
/ 02 марта 2019

Есть ли способ применить ту же логику свойств к набору атрибутов в классе?Например, я хочу применить один и тот же @attr1.setter декоратор к attr2, attr3 и attr4 без необходимости определения свойства для каждого атрибута.

class Sample:
    def __init__(self):
        self.attr1 = None
        self.attr2 = None
        self.attr3 = None
        self.attr4 = None

    @property
    def attr1(self):
        return self.__attr1

    @attr1.setter
    def attr1(self, val):
        if val < 0:
            self.__attr1 = 0
        else:
            self.__attr1 = val

Ответы [ 2 ]

0 голосов
/ 02 марта 2019

Вы можете переопределить __getattr__ и __setattr__, чтобы вести себя так, как вы хотите.Таким образом, вам не нужно ни определять частные переменные, ни инициализировать какие-либо переменные-члены.

class Sample:
    def __getattr__(self, attr):
        return self.__dict__.get(attr)

    def __setattr__(self, attr, val):
        if val is not None and val < 0:
            self.__dict__[attr] = 0
        else:
            self.__dict__[attr] = val

s = Sample()

print(s.attr1) # None
s.attr1 = 10
print(s.attr1) # 10
s.attr1 = -10
print(s.attr1) # 0
s.attr1 = None
print(s.attr1) # None
0 голосов
/ 02 марта 2019

Просто создайте свой собственный дескриптор для этого:

class MyDescriptor:
    def __set_name__(self, owner, name):
        self.name = f'_{name}'
    def __get__(self, instance, owner):
        return getattr(instance, self.name)
    def __set__(self, instance, val):
        if val is None:
            setattr(instance, self.name, None)
        elif val < 0:
            setattr(instance, self.name, 0)
        else:
            setattr(instance, self.name, val)

class Sample:
    attr1 = MyDescriptor()
    attr2 = MyDescriptor()
    attr3 = MyDescriptor()
    attr4 = MyDescriptor()
    def __init__(self):
        self.attr1 = None
        self.attr2 = None
        self.attr3 = None
        self.attr4 = None

Теперь, в действии:

In [3]: s = Sample()

In [4]: s.attr1 = -99

In [5]: s.attr1
Out[5]: 0

In [6]: s.attr2

In [7]: s.attr2 = 10

In [8]: s.attr2
Out[8]: 10

In [9]: s.attr2 = -1

In [10]: s.attr2
Out[10]: 0

См. Дескриптор HOWTO и некоторые другие соответствующие документация

Обратите внимание, я включил возможность None в логику вашего установщика (ваш код поднял бы TypeError при инициализации экземпляра, потому что установщик проверяет, если None < 0),Также обратите внимание, что вы, вероятно, не хотите использовать двойное подчеркивание имен (, что не означает частное ), поэтому я использовал условное одинарное подчеркивание для обозначенияпеременная не является частью публичного API.Использование двойного подчеркивания с искажением имен усложняет ситуацию.

...