python, __slots__ и "атрибут только для чтения" - PullRequest
19 голосов
/ 04 мая 2009

Я хочу создать объект в python, который имеет несколько атрибутов, и я хочу защитить себя от случайного использования неправильного имени атрибута. Код выглядит следующим образом:

class MyClass( object ) :
    m = None # my attribute
    __slots__ = ( "m" ) # ensure that object has no _m etc

a = MyClass() # create one
a.m = "?"  # here is a PROBLEM

Но после запуска этого простого кода я получаю очень странную ошибку:

Traceback (most recent call last):
  File "test.py", line 8, in <module>
    a.m = "?"
AttributeError: 'test' object attribute 'm' is read-only

Есть ли какой-нибудь мудрый программист, который может сэкономить немного своего времени и рассказать мне об ошибках "только для чтения"?

Ответы [ 5 ]

42 голосов
/ 04 мая 2009

Когда вы объявляете переменные экземпляра, используя __slots__, Python создает объект дескриптора как переменную класса с тем же именем. В вашем случае этот дескриптор перезаписывается переменной класса m, которую вы определяете в следующей строке:

  m = None # my attribute

Вот что вам нужно сделать: не определяйте переменную класса с именем m и инициализируйте переменную экземпляра m в методе __init__.

class MyClass(object):
  __slots__ = ("m",)
  def __init__(self):
    self.m = None

a = MyClass()
a.m = "?"

Как примечание: кортежи с единичными элементами нуждаются в запятой после элемента. Оба работают в вашем коде, потому что __slots__ принимает одну строку или итерируемую / последовательность строк. Как правило, для определения кортежа, содержащего элемент 1, используйте (1,) или 1,, а не (1).

14 голосов
/ 05 мая 2009

Вы полностью неправильно используете __slots__. Это предотвращает создание __dict__ для экземпляров. Это имеет смысл только в том случае, если вы столкнетесь с проблемами памяти со многими небольшими объектами, потому что избавление от __dict__ может уменьшить занимаемую площадь. Это жесткая оптимизация, которая не требуется в 99,9% случаев.

Если вам нужна безопасность, которую вы описали, то Python действительно не тот язык. Лучше использовать что-то строгое, например, Java (вместо того, чтобы пытаться писать Java на Python).

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

Просто для полноты вот ссылка на документацию для слотов .

7 голосов
/ 04 мая 2009

__slots__ работает с переменными экземпляра, тогда как у вас есть переменная класса. Вот как вы должны это делать:

class MyClass( object ) :
  __slots__ = ( "m", )
  def __init__(self):
    self.m = None

a = MyClass()
a.m = "?"       # No error
6 голосов
/ 04 мая 2009

Учтите это.

class SuperSafe( object ):
    allowed= ( "this", "that" )
    def __init__( self ):
        self.this= None
        self.that= None
    def __setattr__( self, attr, value ):
        if attr not in self.allowed:
            raise Exception( "No such attribute: %s" % (attr,) )
        super( SuperSafe, self ).__setattr__( attr, value )

Лучшим подходом является использование модульных тестов для такого рода проверки. Это изрядное количество времени выполнения.

0 голосов
/ 20 октября 2014
class MyClass( object ) :
    m = None # my attribute

m здесь - это атрибуты класса, а не атрибут экземпляра. Вам нужно связать его с вашим экземпляром самостоятельно в __init__.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...