Найти - Пользователи
Полная версия: Дескриптор с self.value (Descriptor with self.value)
Начало » Python для экспертов » Дескриптор с self.value (Descriptor with self.value)
1 2 3
alexgreg
Задача: в некотором клиентском классе SomeClass описать свойство myName (имя экземпляра), разместив атрибут value в классе-дескрипторе Name. Предполагается, что каждый экземпляр класса SomeClass имеет своё собственное имя.

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

 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 SomeClass:
    myName = Name()
#---------------------------------------------------------------------------------
if __name__ == '__main__':
    a = SomeClass()
    b = SomeClass()
    
    print(a.myName)
    print(b.myName)
    a.myName = 'my name is A'
    print(a.myName)
    print(b.myName)
    b.myName = 'my name is B'
    print(a.myName)
    print(b.myName)
    del a.myName

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

 ==================== RESTART: Dweb.py/attrs/testdesc.py ====================
default name
default name
my name is A
my name is A
my name is B
my name is B
Traceback (most recent call last):
  File "D:/web.py/attrs/testdesc.py", line 36, in <module>
    del a.myName
  File "D:/web.py/attrs/testdesc.py", line 13, in __delete__
    raise AttributeError('from Name.__delete__')
AttributeError: from Name.__delete__
>>>


В чём ошибка?
krok64
 class SomeClass:
    def __init__(self):
        self.myName = Name()

а в класс Name добавь

     def __repr__(self):
        return self.value
alexgreg
Разве свойства в __init__ описываются?

Внёс предложенные изменения:

 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 SomeClass:
    def __init__(self):
        self.myName = Name()
#---------------------------------------------------------------------------------
if __name__ == '__main__':
    a = SomeClass()
    b = SomeClass()
    
    print(a.myName)
    print(b.myName)
    a.myName = 'my name is A'
    print(a.myName)
    print(b.myName)
    b.myName = 'my name is B'
    print(a.myName)
    print(b.myName)
    print(a.__dict__)
    print(b.__dict__)
    #del a.myName

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

 ==================== RESTART: D:\web.py\attrs\testdesc.py ====================
<__main__.Name object at 0x02EBD2D0>
<__main__.Name object at 0x03128F70>
my name is A
<__main__.Name object at 0x03128F70>
my name is A
my name is B
{'myName': 'my name is A'}
{'myName': 'my name is B'}
>>>

в этом случая, насколько я понимаю, протокол дескриптора бездействует (проверено print'ами)

krok64
alexgreg
Разве свойства в __init__ описываются? Внёс предложенные изменения:
В __init__ свойства инициализируются сразу после создания объекта. Для вывода имени по умолчанию посмотри дополнение ко второму сообщению.
alexgreg
1) в __init__ инициализируются атрибуты экземпляра класса, если self используется, разве не так?

2) если я опишу метод SomeClient.__repr__, при обращении к a.myName какой метод отработает SomeClient.__repr__ или Name.__get__?
PEHDOM
alexgreg
class SomeClass:
def __init__(self):
self.myName = Name()
Это так не работает. Дескриптор это атрибут класса а не инстанса. Вариант топикстартера был правильный, и работал он правильно(с точки зрения пайтона конечно, а не топикстартера).. так и должно быть.
Когда вы делаете a.myName = ‘my name is A’ вы устанавливете дескриптору myName класса SomeClass значение ‘my name is A’. поскольку b инстанс того же класса что и a то print(b.myName) вернет ‘my name is A’.
Теперь когда вы делаете b.myName = ‘my name is B’ вы вы устанавливете дескриптору myName класса SomeClass значение ‘my name is B’ и сотоветвенно print(a.myName) вернет ‘my name is B’ поскольку а инстанс класса SomeClass
alexgreg
где ошибка в первом варианте? предполагается, что каждый экземпляр класса SomeClass должен иметь своё имя, которое хранится в экземпляре соответствующего дескриптора (поле self.value класса Name)
4kpt_V
alexgreg
Для Вашего случая лучше использовать property.

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

Простой пример для понимания
 #
class A:
    n = {}
#
a = A()
b = A()
a.n["a"] = 12
print(b.n)  # {'a': 12}
PEHDOM
alexgreg
где ошибка в первом варианте?
вопрос, вам это надо для чего? если для продакшена, то советую использовать чтонить другое(выше советуют property например ), а не дескрипторы, если это задания от преподавателя и нужно использовать именно дексриптеры то есть один нетрадиционный способ(тоесть через жопу) чтобы дескриптор храних значения каждого инстанса.
alexgreg
4kpt_V
alexgreg
Для Вашего случая лучше использовать property.

все остальные варианты работают (property, @property, дескриптор с использованием атрибутов класса-клиента). непонятен именно этот вариант, когда значение для класса-клиента хранится в атрибуте класса-дескриптора (self.value в примере)
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