Доступ к переопределенным атрибутам не работает (как и ожидалось)

StackOverflow https://stackoverflow.com/questions/1874043

  •  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]
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top