有条件地定义属性(使用decorator)(例如try/except?)

2024-09-29 23:30:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在寻找一种在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

我不知道父对象中定义了哪些属性,因此我需要有条件地构建属性的东西。我们也欢迎任何其他解决办法。你知道吗

[编辑]另一次尝试…但是,不仅创建了属性,而且尝试访问它会引发无限递归错误

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]我在父级中有一个方法,可以让我知道哪些是属性。为了示例,假设在{{CD2}} C++类中有一个方法{{CD1}},它返回父类动态创建的属性名称(字符串)的列表。你知道吗


Tags: 方法selfreturn属性定义initvaluedef
3条回答

怎么样:

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

您可以将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/elsetry/except并不是一件有趣的事,仅仅因为某个父类缺少方法。而这部分不能像你现在这样修复。你知道吗

所以,要考虑的主要问题是,当父类行为未知时,情况如何?如果它在安装时为用户所知,那么可以考虑提供两个不同的子类,内部没有任何意外。你知道吗

如果它只在运行时知道,为什么还要费心检查呢?用户仍将使用

try:
    child_obj.my_property
except AttributeError:
    ...

捕捉您的flappy接口,但有趣的是缺少父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)

将使用几乎相同的

第一点:@decorator语法并不是什么神奇的东西,它只是语法上的糖分,所以

@decorator
def func():
    pass

实际上只是一个方便的快捷方式:

def func():
    pass
func = decorator(func)

第二点:property类型是the ^{} protocol的一个通用实现(而且相当简单,这里同样不涉及魔法)。描述符仅在解析为类属性时才“起作用”,因此将属性设置为实例属性将不起作用,句点(查找它们将返回描述符对象本身,它不会调用描述符的__get____set__方法)。你知道吗

第三点:您的代码甚至没有将创建的属性设置为实例属性(无论如何都不会工作),它们只是在_CreateAttributes方法执行期间存在的普通本地名称。你知道吗

<>这一切都不会解决你的问题——你必须为某人提供更多的上下文来发布解决方案,以解决具体的用例(基于这个C++父类实际上是如何实现的)等等,但是至少现在你知道为什么尝试失败了。你知道吗

编辑:

I have a method inside the parent that allows me to know which are the properties. For the sake of the example let's suppose I have a method ListAttributes in the SomeOtherObj C++ class which returns a list of the attributes names (strings) dynamically created by the Parent class.

如果是classmethod或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__是默认的属性设置器,所以您必须确保明智地使用它。你知道吗

相关问题 更多 >

    热门问题