使用实例名称访问实例变量

时间:2021-04-19 22:38:09

标签: python instance-variables

我有一堂这样的课:

Class PropertyExpr:
    def __init__(self, value, expr):
        self.value = value
        self.expr = expr

假设我像这样初始化类:

prop1 = PropertyExpr(5, "test")

我明白,如果我想访问 valueexpr,我会调用 prop1.valueprop1.expr

但是,我想让它在我调用 prop1 时自动返回 prop1.valueprop1.expr 仍然可以访问 expr 变量

由于 value 可以是任何数据类型,我认为使用 __str__ 行不通。

感谢您的帮助!

编辑:这是我目前的方法,但它只适用于 int,我需要扩展它以便它也适用于其他数据类型,例如列表:

class PropertyExpr(int):

    def __new__(self, value: int, expr: Optional[str]=None, *args, **kwargs):
        return int.__new__(self, value, *args, **kwargs)

    def __init__(self, value: int, expr: Optional[str]=None, *args, **kwargs):
        int.__init__(value, *args, **kwargs)
        if expr is None:
            self.expr = str(value)
        else:
            self.expr = expr

所以当我创建一个实例时:

prop1 = PropertyExpr(5, "test")

所以当我使用 prop1 时,它会返回 5 和 prop1.expr = "test"

2 个答案:

答案 0 :(得分:1)

如果您所说的“调用”实际上是指调用而不仅仅是“访问”,那么您可以简单地实现一个 __call__ 方法:

class PropertyExpr:
    def __init__(self, value, expr):
        self.value = value
        self.expr = expr

    def __call__(self):
        return self.value

prop1 = PropertyExpr(5, "test")

val = prop1()
print(val)

输出:

5

在这种情况下,调用 prop1() 的结果实际上可以是任何东西。

除此之外,你想要的是不可能的。您可以覆盖 __new__ 方法,但这也会改变您创建的内容的类型。因此,如果您返回 5,您的对象将是 5,但它也将是一个 int,不再是 PropertyExpr 的实例,您的所有附加属性都将是丢失:

class PropertyExpr():
    def __new__(cls, value, expr):
        return value

    def __init__(self, value, expr):
        self.value = value
        self.expr = expr

prop1 = PropertyExpr(5, "test")

print(prop1, type(prop1))
try:
    print(prop1.expr)
except Exception as e:
    print(e)

输出:

5 <class 'int'>
'int' object has no attribute 'expr'

经过一些尝试,我找到了一种动态更改构造函数类型的方法,但是我建议不要实际使用它:

class PropertyExpr:
    def __new__(cls, tp, value, *args, **kwargs):
        return type("FakeType", (tp,), kwargs)(value)

prop1 = PropertyExpr(int, 5, expr="expr int")
print(prop1, " -> ", prop1.expr)

prop2 = PropertyExpr(list, "5", expr="expr list")
print(prop2, " -> ", prop2.expr)

prop3 = PropertyExpr(str, "abc", expr="expr string")
print(prop3, " -> ", prop3.expr)

输出:

5  ->  expr int     
['5']  ->  expr list
abc  ->  expr string

您可以将您希望子类化的类型作为第一个参数传递,第二个参数应该是该类型的构造函数接受的值,然后您可以传入任意 kwargs,这些 kwargs 将作为属性添加到创建的对象中。


<块引用>

有没有办法使 type(prop1) 仍然是 PropertyExpr?编辑:例如,如果我们可以做 isinstance(prop1, PropertyExpr) = True 那么一切都会很完美

我无法让它工作(这并不意味着其他人不能),但我设法使其与多继承一起工作,因此您可以使用isinstance(prop1, PropertyExprMixin)

class PropertyExprMixin:
    pass

class PropertyExpr:
    def __new__(cls, tp, value, *args, **kwargs):
        return type("PropertyExprMixin", (tp,PropertyExprMixin), kwargs)(value)

prop1 = PropertyExpr(int, 5, expr="expr int")
print(prop1, " -> ", prop1.expr, type(prop1), isinstance(prop1, int), isinstance(prop1, PropertyExprMixin))

prop2 = PropertyExpr(list, "5", expr="expr list")
print(prop2, " -> ", prop2.expr, type(prop2), isinstance(prop2, list), isinstance(prop2, PropertyExprMixin))

prop3 = PropertyExpr(str, "abc", expr="expr string")
print(prop3, " -> ", prop3.expr, type(prop3), isinstance(prop3, str), isinstance(prop3, PropertyExprMixin))

输出:

5  ->  expr int <class '__main__.PropertyExprMixin'> True True     
['5']  ->  expr list <class '__main__.PropertyExprMixin'> True True
abc  ->  expr string <class '__main__.PropertyExprMixin'> True True

答案 1 :(得分:0)

你可以这样做:

OwnerID Pet(s)
1       X, Y, and Z
2       Apples

输出:

class PropertyExpr(int):

    def __new__(cls, value, expr):
        obj = super().__new__(cls, value)
        obj.expr = expr
        return obj
 
var = PropertyExpr(5, "test")
print(var)
print(var.expr)
相关问题