2013-06-27 3 views
1

Я только начал изучать питон и очень смущен тем, почему я могу это сделать. Будет ли кто-нибудь, пожалуйста, объясните, почему это работает:Свойства/атрибуты класса Python

class foo(): 
    @property 
    def hello(self): 
     return "hello world" 


if __name__ == '__main__': 
    cli = foo() 
    cli.foo2 = 3 
    print cli.hello #prints hello world 
    print cli.foo2 #prints 3 

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

-edit- Я рад, что это нормальное поведение для объектов в python, и я не просто делал что-то неправильно. Это просто не понравилось, поскольку я обычно работаю в VBA и C#. Из того, что другие сказали в ответах ниже, я думал, что добавление слотов помешает чему-либо добавить к классу таким образом, но, возможно, я не понял.

class foo(): 
    @property 
    def hello(self): 
     return "hello world" 
    __slots__ = [] 

if __name__ == '__main__': 
    cli = foo() 
    cli.foo2 = 3 
    print cli.hello #prints hello world 
    print cli.foo2 #prints 
+0

я попробовал это, и это не работает для меня (как и ожидалось) - ни cli.foo, ни cli.foo2 определено. –

+0

@AMADANON: Это немного странно. [Это работает для меня] (http: // codepad.org/U5XOZL5c), а также OP и другие. – icktoofay

+0

отредактирован/исправлен - у меня все еще есть вырезание и вставка в окне терминала :) –

ответ

3

С smarter person than me:

Ведущий принцип заключается в том, что нет такого понятия, как декларация. То есть вы никогда не заявляете, что «этот класс имеет метод foo» или «экземпляры этого класса имеют панель атрибутов», не говоря уже о том, чтобы сделать заявление о типах объектов, которые будут там храниться. Вы просто определяете метод, атрибут, класс и т. Д., И он добавляется. Как указывает JBernardo, любой метод __init__ делает то же самое. Было бы бессмысленно произвольно ограничивать создание новых атрибутов методами с именем __init__. Иногда бывает полезно сохранить функцию как __init__, которая на самом деле не имеет этого имени (например, декораторы), и такое ограничение нарушит это.

Теперь это не универсально. Встроенные типы опускают эту возможность в качестве оптимизации. Через __slots__ вы также можете предотвратить это на пользовательских классах. Но это просто оптимизация пространства (нет необходимости в словаре для каждого объекта), а не в правильности.

Если вам нужна защитная сетка, ну, слишком плохо. Python не предлагает один, и вы не можете разумно добавить его, и, самое главное, его избегают программисты Python, которые используют этот язык (читайте: почти все из тех, с которыми вы хотите работать). Тестирование и дисциплина по-прежнему имеют большое значение для обеспечения правильности. Не используйте свободу, чтобы составлять атрибуты за пределами __init__, если этого можно избежать и выполнять автоматическое тестирование. У меня очень редко есть AttributeError или логическая ошибка из-за обмана, подобного этому, и из тех, которые происходят, почти все попадают под тесты.

+0

Думаю, я просто соглашусь с этим как на нормальное поведение и тогда и дальше. – Ripster

0

Это предназначенное поведение для объекта python, вы можете добавлять атрибуты и т. Д. Всякий раз, когда вы их создаете. Вы можете, однако, ограничить это поведение, делая это:

class foo(): 
    __slots__ = [] 
    @property 
    def hello(self): 
     return "hello world" 

Это __slots__ переменная является одним из способов сделать ваш класс неизменны, так что вы не можете добавить свойства к нему иначе класс питон обычно ведут себя, как вы описали в своем вопросе

Другой вариант, чтобы переопределить методы для установки и удаления атрибутов, как этот

def __setattr__(self, *args): 
    raise TypeError 
def __delattr__(self, *args): 
    raise TypeError 
+0

Даже после добавления '__slots__ = []' Мне удалось запустить код без ошибок. Не уверен, что я неправильно понял, как должны работать слоты? – Ripster

+0

@Ripster он должен работать как есть, поэтому мои дополнительные решения, которые я только что опубликовал – Stephan