我正在寻找一种在python中有条件地定义属性的方法。 想法是在try / except块内定义属性
class PyObject(SomeOtherObj):
def __init__(self, dbaObj):
super(SomeOtherObj, self).__init__()
self._CreateAttributes()
def _CreateAttributes(self):
try:
self.GetProperty("MyProperty") #This method comes from the parent
except:
pass
else:
@property
def MyProperty(self):
return self.GetProperty("MyProperty")
@MyProperty.setter
def MyProperty(self, value):
return self.ModifyProperty("MyProperty", value) #This method comes from the parent
我不知道在父对象中定义了哪些属性,因此我需要一些有条件地构建属性的东西。也欢迎任何其他解决方案。
[EDIT]另一种尝试...但是无论如何无论如何都会创建该属性,但是尝试访问它会引发无限递归错误
class PyObject(SomeOtherObj):
def __init__(self, dbaObj):
super(SomeOtherObj, self).__init__()
@property
def MyProperty(self):
try:
return self.GetProperty("MyProperty")
except:
del self.MyProperty
@MyProperty.setter
def MyProperty(self, value):
return self.ModifyProperty("MyProperty", value) #This method comes from the parent
@MyProperty.deleter
def MyProperty(self):
self.__delattr__(self.MyProperty)
[EDIT2]我在父级内部有一个方法,可以让我知道哪些是属性。出于示例的原因,我们假设我在ListAttributes
C ++类中有一个方法SomeOtherObj
,该方法返回一个由Parent类动态创建的属性名称(字符串)的列表。
答案 0 :(得分:1)
您可以将python类视为具有特殊绑定的代码命名空间。是的,您可以在类主体中编写几乎所有内容(考虑一下循环,以提高疯狂程度),它将在类导入时执行(实际上是在模块导入中)。唯一的问题是,在子类关闭中您无法轻松访问父类(不使用元类)。
因此,如果您需要快速而又肮脏的补丁,实际上可以像这样制作try/except
:
class Child(Parent):
try:
Parent.get_property
@property
def my_property(self):
return self.get_property()
@my_property.setter
def my_property(self, value):
self.set_property(value)
except:
pass
第一个问题-父类是硬编码的,如果您更改继承,则需要更改实现。这实际上是不好的设计,但是如果您几乎没有约束,也许对您来说还可以。
更大的问题是,这种接口很难使用。在大多数情况下,如果您提供属性/方法,则您的用户将期望类具有此属性/方法。经常使用if/else
或try/except
只是一个有趣的方法,因为某些父类缺少方法。而且这部分无法以您现在拥有的方式来固定。
因此,主要要考虑的问题-当父类行为未知时,情况如何?如果用户在安装时就知道它,请考虑提供两个不同的子类,内部没有任何惊喜。
如果仅在运行时已知,为什么还要为此检查呢?用户仍将使用
try:
child_obj.my_property
except AttributeError:
...
捕捉您的浮动界面,但有趣的是缺少父getter会产生相同的异常,所以很简单
class Child(Parent):
@property
def my_property(self):
return self.get_property()
@my_property.setter
def my_property(self, value):
self.set_property(value)
使用方式几乎相同
答案 1 :(得分:1)
第一点:@decorator
语法没什么神奇的,只是语法糖,所以
@decorator
def func():
pass
实际上只是用于以下目的的便捷快捷方式:
def func():
pass
func = decorator(func)
第二点:property
类型是the descriptor
protocol的通用(并且相当简单-在这里,没有涉及魔术)。描述符仅在解析为类属性时才“起作用”,因此将属性设置为实例属性将无法正常工作(句点(查找它们将返回描述符对象本身,不会调用描述符的__get__
和__set__
)方法)。
第三点:您的代码甚至没有将创建的属性设置为实例属性(无论如何都无法工作),它们只是普通的 local 名称,仅在_CreateAttributes
期间存在方法执行。
这些都不能解决您的问题-您必须提供更多上下文,以便某人发布专为您的具体用例工作的解决方案(基于此C ++父类的实际实现方式等)-但至少您现在知道尝试失败的原因了。
编辑:
我在父级内部有一个方法,可以让我知道哪些是属性。为了举例说明,假设我在SomeOtherObj C ++类中有一个ListAttributes方法,该方法返回由Parent类动态创建的属性名称(字符串)的列表。
如果这是类方法或静态方法,则可以使用类装饰器来创建属性(或者,为简化样例,使用自定义描述符):
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__
是默认的属性设置器,因此必须确保明智地使用它。
答案 2 :(得分:0)
那呢:
class A:
def stuff(self):
pass
a = A()
if hasattr(a, 'another'):
print(a.another)
else:
A.another = property(lambda self: 1)
print(a.another)
您可以通过在运行时中设置属性来简单地修补类
Result: 1