Управления доступом к атрибутам в Python
Фактически это конспект 37 главы книги Марка Лутца "Изучаем Python"
Код на github
Управления доступом к атрибутам в Python может осуществляться несколькими способами:
Все аргументы по умолчанию None, при обращение приводят к исключению
Примеры
В отличии от свойств в дескрипторе при отсутствии метода не возникает исключение.
Если не реализован __set__, то атрибут будет просто переопределен
__set__ -при присваивании значений
__getattribute__ -вызывается при обращение к любым атрибутам
Делегирования - управление доступом ко всем атрибутам встроенного объекта
функция getattr(self, item) эквивалентна self.item
Предотвращение зацикливаний
Если внутри метода __getattribute__ обратится к другому атрибуту то эта операция произведет вызов метода __getattribute__ и это приведи к бесконечному циклу
Код на github
Управления доступом к атрибутам в Python может осуществляться несколькими способами:
- __getattr__ __set__ __getattribute__ __delete__
- property
- дескриптор
Свойства
attribute = property(fget, fset, fdel, doc)Все аргументы по умолчанию None, при обращение приводят к исключению
Примеры
# пример использования property # attribute = property(fget, fset, fdel, doc) class Person: def __init__(self, name): self._name = name def get_name(self): return self._name def set_name(self, name): self._name = name def del_name(self): print('del name', self.name) del self._name name = property(get_name, set_name, del_name) class SubPerson(Person): pass bob = Person('bob') print(bob.name) bob.name = 'Bobi' print(bob.name) del bob.name print() tod = Person('tod') print(tod.name) tod.name = 'Todi' print(tod.name) del tod.name print('-' * 10) # ------------------------------- # вычисляемые атрибуты class PropSquare: def __init__(self, start): self.value = start def get_x(self): return self.value ** 2 def set_x(self, value): self.value = value X = property(get_x, set_x) P = PropSquare(3) print('P = PropSquare(3)') Q = PropSquare(32) print('Q = PropSquare(32)') print('P.X = ', P.X) P.X = 4 print('P.X = 4') print('P.X = ', P.X) print('P.Q = ', Q.X) print('-' * 10) # ------------------------------- # декоратор class PersonDec: def __init__(self, name): self._name = name @property def name(self): return self._name @name.setter def name(self, value): self._name = value @name.deleter def name(self): print('deleter name', self.name) del self._name bob = PersonDec('bob dec') print(bob.name) bob.name = 'Bobi Dec' print(bob.name) del bob.name
Дескрипторы
Протокол дескрипторов позволяет передавать выполнение операций чтения и записи для определенного атрибута методам отдельного обьекта класса.В отличии от свойств в дескрипторе при отсутствии метода не возникает исключение.
Если не реализован __set__, то атрибут будет просто переопределен
class Descriptor: """ self - экземпляр дескриптора instance - экземпляр клиенского класса owner - клиенский класс """ def __get__(self, instance, owner): pass def __set__(self, instance, value): pass def __delete__(self, instance): pass # Name - вложенный дескриптор для класса Person class Person: def __init__(self, name): self._name = name class Name: def __get__(self, instance, owner): return instance._name def __set__(self, instance, value): instance._name = value def __delete__(self, instance): print('delete name', instance._name) del instance._name name = Name() bob = Person('bob dec') print(bob.name) bob.name = 'Bobi Dec' print(bob.name) del bob.name print('-' * 10) # Вычисляемые атрибуты # Значения дескриптор хранит у себя class DescSquare: def __init__(self, start): self.value = start def __get__(self, instance, owner): return self.value ** 2 def __set__(self, instance, value): self.value = value class Client1: X = DescSquare(2) Y = DescSquare(3) class Client2: X = DescSquare(32) c1 = Client1() c2 = Client2() print('c1.X = {0}, c1.Y = {1}'.format(c1.X, c1.Y)) print('c2.X = ', c2.X) c1.Y = 10 print('c1.Y = 10') print('c1.Y = ', c1.Y) print('-' * 10) # Простая имитация свойства class Property: def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel self.__doc__ = doc def __get__(self, instance, owner=None): if instance is None: return self if self.fget is None: raise AttributeError("can't get attribute") return self.fget(instance) # аргумент self def __set__(self, instance, value): if self.fset is None: raise AttributeError("can't set attribute") self.fset(instance, value) def __delete__(self, instance): if self.fdel is None: raise AttributeError("can't delete attribute") self.fdel(instance) class Person: def __init__(self, name): self._name = name def get_name(self): return self._name def set_name(self, value): self._name = value name = Property(get_name, set_name) bob = Person('bob') print(bob.name) bob.name = 'Bobi' print(bob.name) # del bob.name # delete не реализован. вызовит ошибку print() tod = Person('tod') print(tod.name) tod.name = 'Todi' print(tod.name)
__getattr__ и __getattribute__
__getattr__ -вызывается при обращение к несуществующим атрибутам__set__ -при присваивании значений
__getattribute__ -вызывается при обращение к любым атрибутам
Делегирования - управление доступом ко всем атрибутам встроенного объекта
функция getattr(self, item) эквивалентна self.item
class Wrapper: def __init__(self, object): self.wrapped = object def __getattr__(self, item): print('Trace:', item) return getattr(self.wrapped, item) class Person: def __init__(self, lname, fname): self.lname = lname self.fname = fname def get_full_name(self): return self.lname + ' ' + self.fname p = Person('Last', 'First') wp = Wrapper(p) print(wp.lname) print(wp.fname) print(wp.get_full_name()) # print(wp.test) # AttributeError
Предотвращение зацикливаний
Если внутри метода __getattribute__ обратится к другому атрибуту то эта операция произведет вызов метода __getattribute__ и это приведи к бесконечному циклу
class Person: # X = 100 def __init__(self, name): print('__init__') self._name = name # вызов __setattr__ def __getattr__(self, attr): # вызов отсутствущих атрибутов print('__getattr__') if attr == 'name': return self._name else: raise AttributeError(attr) def __getattribute__(self, attr): print('__getattribute__', self, attr) if attr == 'name': attr = '_name' return object.__getattribute__(self, attr) # предотвращаем зацикливание def __setattr__(self, attr, value): print('__setattr__') if attr == 'name': attr = '_name' self.__dict__[attr] = value # предотвращаем зацикливание def __delete__(self, attr): print('__delete__') if attr == 'name': attr = '_name' del self.__dict__[attr] # предотвращаем зацикливание p = Person('German') print(p.name)
Mens Titanium Wedding Rings - Etricki - TikTok
ОтветитьУдалитьMens Titanium Wedding t fal titanium pan Rings Men who never got married need a quality wedding ring. It is made with a premium grade 23 titanium material micro touch titanium trim which is titanium engagement rings for her extremely high titanium anodizing quality.