Работа Эффективно с Унаследованным кодом является действительно удивительной книгой, которая вдается в большие подробности о том, как к правильно модульному тесту Ваш код и каково истинное преимущество его. Это действительно открыло мои глаза.
Ох, это сложно (и весело). SWIG не рассматривает это как возможность сгенерировать @property: я думаю, было бы слишком легко ошибиться и распознать множество ложных срабатываний, если бы это не было сделано очень осторожно. Однако, поскольку SWIG не будет делать этого при генерации C ++, все еще вполне возможно сделать это в Python, используя небольшой метакласс.
Итак, ниже, допустим, у нас есть класс Math, который позволяет нам устанавливать и получать целочисленную переменную названный «пи».
У меня была та же проблема, и совет использовать% pythoncode мне помог. Вот что я сделал:
class Foo {
// ...
std::string get_name();
bool set_name(const std::string & name);
};
В оболочке:
%include "foo.h"
%pythoncode %{
def RaiseExceptionOnFailure(mutator):
def mutator(self, v):
if not mutator(self, v):
raise ValueError("cannot set property")
return wrapper
Foo.name = property(Foo.get_name, RaiseExceptionOnFailure(Foo.set_name))
%}
Проблема с метаклассом Hao ProperyVoodoo заключается в том, что при наличии нескольких свойств в списке свойств все свойства ведут себя так же, как последнее в списке. Например, если бы у меня был список или имена свойств [«x», «y», «z»], то свойства, сгенерированные для всех трех, использовали бы те же методы доступа, что и «z».
После небольшого эксперимента, я полагаю, я определил, что эта проблема вызвана тем, как Python обрабатывает замыкания (т. Е.имена внутри вложенных функций, которые ссылаются на переменные в содержащей их области). Чтобы решить эту проблему, вам необходимо получить локальные копии переменной имени свойства в методах fget и fset. Достаточно легко скрыть их, используя аргументы по умолчанию:
# (NOTE: Hao's comments removed for brevity)
class PropertyVoodoo(type):
def __init__(cls, *a):
for prop in cls.__properties__:
def fget(self, _prop = str(prop)):
s = super(cls, self)
return getattr(s, _prop)()
def fset(self, value, _prop = str(prop)):
s = super(cls, self)
return getattr(s, _prop)(value)
setattr(cls, prop, property(fget=fget, fset=fset))
super(PropertyVoodoo, cls).__init__(*a)
def __setattr__(self, name, value):
if name in cls.__properties__:
object.__setattr__(self, name, value)
else:
s = super(cls, self)
s.__setattr__(name, value)
cls.__setattr__ = __setattr__
Обратите внимание, что на самом деле совершенно безопасно давать fget и fset дополнительные параметры _prop, потому что класс property () никогда не будет явно передавать им значения, что означает, что они всегда будет значением по умолчанию (которое является копией строки, на которую ссылается prop во время создания каждого метода fget и fset).