Доступ к переопределенным атрибутам не работает (как и ожидалось)
-
18-09-2019 - |
Вопрос
Основная цель следующего модуля — предоставить своего рода «постоянную» семантику для некоторых имен.
class ConstantError(Exception):
def __init__(self, msg):
self._msg = msg
class Constant(object):
def __init__(self, name):
self._name = name
def __get__(self, instance, owner):
return instance._content[self._name]
def __set__(self, instance, value):
raise ConstantError, 'Illegal use of constant'
class Constants(object):
def __init__(self, content):
self._content = content
for k in self._content:
setattr(self, k, Constant(k))
num_const = Constants({
'one': 1,
'two': 2
})
При использовании:
>>> from const import *
>>> dir(num_const)
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', '_content', 'one', 'two']
Так one
и two
есть, но доступ к атрибутам разочаровывает:
>>> num_const.one
<const.Constant object at 0x7faef4871710>
>>>
Где я ожидаю 1
в этом случае.Где я ошибаюсь?
Решение
Протокол дескриптора работает только атрибуты класса, а не по атрибутам экземпляров класса.См. Практическое руководство по дескрипторам
Другие советы
Вам не хватает ул.() или Юникод() в Константах.
Добавлять:
def __unicode__(self):
return self._name
Я думаю, что Python предотвращает доступ классов к механизму дескрипторов, чтобы ими можно было манипулировать.В противном случае манипулирование дескриптором может оказаться очень сложным без какой-либо «магической» функции, и, если вы заметили, Python пытается сохранить доступ к большей части языкового механизма.Чтобы обойти эту проблему, я часто создавал класс «на лету».Например, ваш класс Constants можно объявить так:
class Constants(object):
def __new__(cls, content):
class _Constants(object):
pass
constants = _Constants
constants._content = content
for k in constants._content:
setattr(_Constants, k, Constant(k))
return constants
но на самом деле для ваших целей вам может быть лучше:
class Constants(object):
def __init__(self, content):
self._content = content
def __getattr__(self,key):
return self._content[key]