В настоящее время я переопределять класс __setattr__
() в конце класса метод __init__
(), чтобы предотвратить новое создание атрибута -Как написать метакласс, который предотвратит создание новых атрибутов после __init __()?
class Point(object):
def __init__(self):
self.x = 0
self.y = 0
Point.__setattr__ = self._setattr
def _setattr(self, name, value):
if not hasattr(self, name):
raise AttributeError("'" + name + "' not an attribute of Point object.")
else:
super(Point, self).__setattr__(name, value)
Есть ли способ, чтобы избежать вручную перекрывая __setattr__
() и сделать это автоматически с помощью метаклассов?
Ближайший я пришел был -
class attr_block_meta(type):
def __new__(meta, cname, bases, dctry):
def _setattr(self, name, value):
if not hasattr(self, name):
raise AttributeError("'" + name + "' not an attribute of " + cname + " object.")
object.__setattr__(self, name, value)
dctry.update({'x': 0, 'y': 0})
cls = type.__new__(meta, cname, bases, dctry)
cls.__setattr__ = _setattr
return cls
class ImPoint(object):
__metaclass__ = attr_block_meta
Есть более общий способ сделать это, например, что априорное знание подкласса атрибутов не требуется?
В принципе, как избежать строки dctry.update({'x': 0, 'y': 0})
и сделать эту работу независимо от того, что такое имена атрибутов класса?
P.S. - FWIW Я уже оценил параметры __slots__
и namedtuple и нашел их в недостатке для моих нужд. Пожалуйста, не сузите свой фокус к рассмотренным пунктам(), которые я использовал для иллюстрации вопроса; фактический прецедент предполагает гораздо более сложный класс.
Почему? При каких обстоятельствах кто-то добавит атрибут вашему классу? Как автор класса, как это повлияет на вас? Как гласит максим, «мы все соглашаемся с взрослыми» на земле Питона; в этом случае это означает, что если я нарушаю API класса, добавив атрибут, я несу ответственность за любые последствия. Python - это не Java и C++. – msw
@msw - В основном, чтобы поймать ошибки, связанные с опечатками, как можно скорее. Если бы я мог избегать программирования, случайно набрав _obj.staet_, а затем задаваясь вопросом, почему машина штата работает не так, я бы это сделал. В принципе, я хотел бы сократить время, которое идет между опечатками к возможной реализации. –
В Python вы действительно не можете использовать язык для принуждения поведения. Это одна из причин того, что тесты и обзоры кода еще более критичны в Python. Итак, скажем, вы поймаете случай «obj.staet», который вы описываете, как насчет 'ojb.state' и когда вы остановитесь. Люди могут (и будут) писать сломанный код на любом языке, и трудно защитить их от самих себя. Наконец, вы уже защищены от половины проблем 'staet': ссылаясь на объект' if obj.staet == 5: 'будет генерировать NameError; Назначение 'obj.staet = 6' не будет уловлено Python. – msw