Первая точка: синтаксис @decorator
не является чем-то волшебным, это просто синтаксический сахар, поэтому
@decorator
def func():
pass
на самом деле просто удобное сокращение для:
def func():
pass
func = decorator(func)
Вторая точка:тип property
является обобщенной (и довольно простой - и здесь опять-таки никакой магией) реализацией протокола descriptor
.Дескрипторы «работают» только тогда, когда они разрешены как атрибуты класса, поэтому установка свойств в качестве атрибутов экземпляра не будет работать, точка (точка поиска их вернет сам объект дескриптора, он не вызовет методы дескриптора __get__
и __set__
).
Третий пункт: ваш код даже не устанавливает созданные свойства как атрибуты экземпляра (которые в любом случае не будут работать), это просто простые локальные имена, которые существуют только во время метода _CreateAttributes
выполнение.
Ничто из этого не решит вашу проблему - вам нужно предоставить больше контекста, чтобы кто-то мог опубликовать решение, гарантирующее работу для вашего конкретного варианта использования (в зависимости от того, как на самом деле реализован этот родительский класс C ++ и т. Д.) -но, по крайней мере, теперь вы знаете, почему ваши попытки терпят неудачу.
РЕДАКТИРОВАТЬ:
У меня есть метод внутри родителя, который позволяет мне узнать, какие свойства.Для примера давайте предположим, что у меня есть метод ListAttributes в классе SomeOtherObj C ++, который возвращает список имен атрибутов (строк), динамически создаваемых классом Parent.
Если это метод класса илиstaticmethod, вы можете использовать декоратор класса для создания свойств (или, чтобы уменьшить шаблон, пользовательский дескриптор):
class Parent(object):
def __init__(self):
self._props = {"foo": 42, "bar": None}
@classmethod
def ListAttributes(cls):
return ["foo", "bar"]
def GetProperty(self, name):
return self._props[name]
def ModifyProperty(self, name, value):
self._props[name] = value
class Prop(object):
def __init__(self, name):
self.name = name
def __get__(self, instance, cls):
return instance.GetProperty(self.name)
def __set__(self, instance, value):
instance.ModifyProperty(self.name, value)
def setprops(cls):
parent = cls.__bases__[0]
for name in parent.ListAttributes():
setattr(cls, name, Prop(name))
return cls
@setprops
class Child(Parent):
pass
c = Child()
print("foo : {}".format(c.foo))
print("bar : {}".format(c.bar))
c.bar = "yay!"
print("bar: {}".format(c.bar))
Если Parent.ListAttributes
является методом экземпляра, вы все равно можете использовать __getattr__
и __setattr__
специальные методы:
class Parent2(object):
def __init__(self):
self._props = {"foo": 42, "bar": None}
def ListAttributes(self):
return ["foo", "bar"]
def GetProperty(self, name):
return self._props[name]
def ModifyProperty(self, name, value):
self._props[name] = value
class Child2(Parent2):
def __getattr__(self, name):
if name in self.ListAttributes():
return self.GetProperty(name)
raise AttributeError("object {} has no attribute {}".format(type(self), name))
def __setattr__(self, name, value):
if name in self.ListAttributes():
self.ModifyProperty(name, value)
super(Child2, self).__setattr__(name, value)
c = Child2()
print("foo : {}".format(c.foo))
print("bar : {}".format(c.bar))
c.bar = "yay!"
print("bar: {}".format(c.bar))
# check we didn't break the default __setattr__
c.baaz = "ok"
print("baaz: {}".format(c.baaz))
Осторожно: __getattr__
вызывается только в крайнем случае, если все другие поиски не пройдены, поэтому он в основном безвреден, но __setattr__
является установщиком атрибута по умолчанию, так что выубедитесь, что вы используете это с умом.