Найти - Пользователи
Полная версия: Дескриптор с self.value (Descriptor with self.value)
Начало » Python для экспертов » Дескриптор с self.value (Descriptor with self.value)
1 2 3
alexgreg
4kpt_V
Что из того, что я написал Вам не понятно?
всё понятно, что Вы пишите. В первом примере (с чего началось обсуждение) и в последнем (с клиентским классом D вместо класса SomeClass) присутствуют ДВА АНАЛОГИЧНЫХ ОБЪЯВЛЕНИЯ свойства (myName в SomeClass и name в D) с единственным отличием, а именно: в первом случае для хранения значения используется АТРИБУТ ЭКЗЕМПЛЯРА КЛАССА-ДЕСКРИПТОРА, а во втором - АТРИБУТ ЭКЗЕМПЛЯРА КЛАССА-КЛИЕНТА. Непонятно, почему второй вариант отрабатывает, а первый нет.
alexgreg
предлагаю продолжить завтра…
4kpt_V
Внутри методов операции одинаковые?
Вы приводите два разных примера…
PEHDOM
Хмм млин с чего бы начать?
Итак есть классы и есть инстансы(экземпляры классов). Класс это кагбэ шаблон по которому создаеться экземпляр. класс может содержать свои атрибуты а экземпляр свои. Вот банальный пример:
 class Test():
    a = 'я атрибут "а" класса Test' # это атрибут класса
    def __init__(self):
        self.b = 'я атрибут "b" экземпляра класса Test' # это атрибут инстанса
if __name__ == '__main__':
    print(Test.a)
    print(Test.b)
на выходе получаем
 я атрибут "а" класса Test
Traceback (most recent call last):
  File "<модуль2>", line 7, in <module>
AttributeError: type object 'Test' has no attribute 'b'
мы не создавали никаких экземпляров, но класс(шаблон) уже создан, и мы можем обратиться к атрибуту класса.
Теперь создадим инстанс:
 ......
if __name__ == '__main__':
    test = Test()
    print(test.a)
    print(test.b)
    print('атрибуты инстанса:',test.__dict__)
>>> 
>>> 
я атрибут "а" класса Test
я атрибут "b" экземпляра класса Test
атрибуты инстанса: {'b': 'я атрибут "b" экземпляра класса Test'}
>>> 
>>> 
Несмотря на то что сам инстанс не имеет атрибута “а” test.a не бросает исключение.
Когда мы обращаетесь к атрибуту инстанса, сначала атрибут ищеться атрибутах инстанса, если не находит, тогда ищется в атрибутах класса, если и там нету - тогда в атрибутах классов от котороых наследует класс, и если и там не находит то бросает исключение AttributeError.
 .....
if __name__ == '__main__':
    test = Test()
    test.a = 'я атрибут "а" экземпляра класса Test'
    print(test.a)
    print(test.b)
    print('атрибуты инстанса:',test.__dict__)
    print(Test.a)
>>> 
я атрибут "а" экземпляра класса Test
я атрибут "b" экземпляра класса Test
атрибуты инстанса: {'a': 'я атрибут "а" экземпляра класса Test', 'b': 'я атрибут "b" экземпляра класса Test'}
я атрибут "а" класса Test
>>> 
когда мы написали test.a = ‘я атрибут “а” экземпляра класса Test’ то создался атрибут “а” инстанса.
Теперь инстанс класса имеет свой атрибут “а” с своим значением: “я атрибут ”а“ экземпляра класса Test”. В тоже время атрибут класса остался неизменным.
Пока все понятно, это так сказать азы. А теперь добавим дескриптор
 class Name(): # name descriptor
    def __init__(self):
        self.value = 'default name'
    def __get__(self, instance, owner):
        return self.value
    def __set__(self, instance, value):
        self.value = value
    def __delete__(self, instance):
        raise AttributeError('from Name.__delete__')
class Test():
    a = 'я атрибут "а" класса Test' # это атрибут класса
    c = Name()                      # это тоже атрибут класса
    def __init__(self):
        self.b = 'я атрибут "b" экземпляра класса Test' # это атрибут инстанса
if __name__ == '__main__':
    test = Test()
    print('test.c =', test.c)
    test.c = 'John Smith'
    print('new name, test.c =',test.c)
    print('атрибуты инстанса:',test.__dict__)
    test2 = Test()
    print('another instance,  test.c =',test2.c)
>>> 
test.c = default name
new name, test.c = John Smith
атрибуты инстанса: {'b': 'я атрибут "b" экземпляра класса Test'}
another instance,  test.c = John Smith
>>>
В предыдущем примере когда мы сделали “test.a = ‘я атрибут ”а“ экземпляра класса Test’” мы создали новый атрибут инстанса. (“атрибуты инстанса: {'a': ‘я атрибут ”а“ экземпляра класса Test’, ‘b’: ‘я атрибут ”b“ экземпляра класса Test’}”)
Теперь же когда мы делаем test.c = ‘John Smith’ новый атрибут не созаеться (“атрибуты инстанса: {'b': ‘я атрибут ”b“ экземпляра класса Test’}”) потому что “с” дескриптор, и изменяя атрибут “с” инстанса на самом деле изменяетться атрибут класса Test. Грубо говоря обращаясь дескриптору как к атрибуту инстанса, на самом деле вы обращаетесь к атрибуту класса. Безоговорочно.
Соответвенно если вы создадите другой инстанст класса Test и захотите изменить атрибут “с” он опять изменить атрибут класса а не инстанса.
alexgreg
Я всё понял. Когда для описания свойств (а лучше сказать - управляемых атрибутов) класса-клиента используется дескриптор, и описание свойств выглядит так:

 class SomeClass:
        someProp = SomePropDescriptor()
        ....

, то someProp всегда является атрибутом класса, и лишь за счёт параметра instance в методах дескриптора возможно разделить данные по экземплярам класса-клиента. Как следствие, все экземпляры всех классов-клиентов, используют один экземпляр класса-дескриптора
4kpt_V
alexgreg
alexgreg
Я всё понял. Когда для описания свойств (а лучше сказать - управляемых атрибутов) класса-клиента используется дескриптор, и описание свойств выглядит так:
Аллелуйя!!!
Вы просто приводили разные примеры. 1 был без использования переменной метода instance, а другой с ней
alexgreg
Вот решение, к которому привело обсуждение:

Пишу код (Python 3.6.0):

 class Nn:  
    value = 0
    def __get__(self, instance, owner):
        return Nn.value
    def __set__(self, instance, value):
        raise AttributeError('Нельзя изменить счётчик')
    
    def __delete__(self, instance):
        raise AttributeError('Нельзя удалить счётчик')
    
class Name:
    def __init__(self):
        self.values = dict({})
    def __get__(self, instance, owner):
        Nn.value += 1
        return '[%d] %s' % (Nn.value, self.values.get(instance, 'по-умолчанию'))
    def __set__(self, instance, value):
        self.values[instance] = value # ключом является экземпляр класса-клиента
    
    def __delete__(self, instance):
        raise AttributeError('Нельзя удалить имя экземпляра')
class SomeClass:
    nn = Nn()
    name = Name()
#---------------------------------------------------------------------------------
if __name__ == '__main__':
    a = SomeClass()
    b = SomeClass()
    
    print(a.name)
    print(b.name)
    
    a.name = 'my name is A'
    print(a.name)
    print(b.name)
    
    print(a.nn)
    print(b.nn)
    
    print(a.__dict__)
    print(b.__dict__)
   


Получаю результат:

 ==================== RESTART: Dweb.py/attrs/testdesc.py ====================
[1] по-умолчанию
[2] по-умолчанию
[3] my name is A
[4] по-умолчанию
4
4
{}
{}
>>>

alexgreg
БЛАГОДАРЮ ЗА ПОМОЩЬ
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB