Прежде всего, это почти всегда плохая идея делать такую вещь. Если только причина, почему вы хотите, чтобы убедиться, что вы не делаете опечатки - для этого есть лучшие инструменты (думаю, IDE или pylint). Если вы на 100% уверены, что вам нужна такая вещь, вот два способа сделать это:
Первый способ - вы можете сделать это с использованием метода __setattr__
. См python __setattr__
documentation
class Person(object):
def __init__(self, first_name, last_name):
self.__dict__['first_name'] = first_name
self.__dict__['last_name'] = last_name
def __setattr__(self, name, value):
if name in self.__dict__:
super(Person, self).__setattr__(name, value)
else:
raise AttributeError("%s has no attribute %s" %(self.__class__.__name__, name))
и выход:
In [49]: a = Person(1, 2)
In [50]: a.a = 2
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/usr/local/lib/python2.7/dist-packages/django/core/management/commands/shell.pyc in <module>()
----> 1 a.a = 2
/usr/local/lib/python2.7/dist-packages/django/core/management/commands/shell.pyc in __setattr__(self, name, value)
8 super(Person, self).__setattr__(name, value)
9 else:
---> 10 raise AttributeError("%s has no attribute %s" %(self.__class__.__name__, name))
AttributeError: Person has no attribute a
В качестве альтернативы, вы можете сделать это с помощью __slots__
(python __slots__
documentation):
class Person(object):
__slots__ = ("first_name", "last_name")
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
выход:
In [32]: a = Person("a", "b")
In [33]: a.first_name
Out[33]: 'a'
In [34]: a.a = 1
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/usr/local/lib/python2.7/dist-packages/django/core/management/commands/shell.pyc in <module>()
----> 1 a.a = 1
AttributeError: 'Person' object has no attribute 'a'
Первый способ более гибкий, поскольку он позволяет взломать этот код еще дальше, используя напрямую __dict__
, но это было бы еще более неправильно, чем сейчас. Второй подход предопределяет пространство для определенного количества переменных экземпляра (ссылок), что означает меньшее потребление памяти.
Я думаю, что это пример того, что люди называют «обезглавливанием обезьян», и я думаю, что это одна из вещей, которые люди любят в Python. Так что это звучит немного похоже на то, что вы боретесь с языком. – BenDundee
Если вы действительно должны, '__slots__' может достичь того, что вы хотите сделать. Тем не менее, это действительно не должно быть использовано для этого ... Я бы подумал, что это «__slots__». В конечном счете, именно поэтому вам необходимо предоставить согласованный API и хорошую документацию. Если пользователь получит ошибку, они поймут, что они неправильно использовали ваш API. – mgilson
@BenDundee: monkeypatching в основном о добавлении/изменении поведения во время выполнения. Опираясь на те же механизмы, приведенный выше пример определенно является опечаткой, а не monkeypatch;) –