(澳门新葡京官网) Python 中基于实例对象的动态property就真的无法实现吗?
澳门新葡京官网
澳门新葡京官网
当前位置 : 澳门新葡京官网 > 澳门新葡京官网

(澳门新葡京官网) Python 中基于实例对象的动态property就真的无法实现吗?

使用 @property 描述符可以自定义类变量的读取、写入和删除操作,而且可以在运行时间,新增或修改这样的类变量。但这样的 property 变量只能是类域下的变量,他的名字只存于对象所属类的 __dict__ 中,因此如果你为某个实例对象使用 property 描述符,基于 Python 的调用规则是无法调用相关 get 或 set 函数的,我的问题是有任何方法能实现基于实例对象的动态 property 功能吗?感谢任何可能的建议或信息!

举例:

class Aobject:
    var = 2

我们现在有一个类,它有一个类域的变量 var,所有根据类 A 生成的对象(实例)都可以访问这个变量

A.var = 3 或 printA.var

如果我创建一个函数,返回 var 的平方。

def powerself: return self.var**2

并把它以 property 的形式赋予类 A:

A.power = propertypower

那么现在可以通过访问类实例的power属性a.power 来获得 var 的平方:

a=A
>>> a.power
9

所有类的实例都能访问 varpower 两个属性,这样我就动态的为类 A 加了一个属性,只读的。

但如果为某个 A 类对象实例增加 property:

a = A
def superself:
    return self.var**3
a.super = propertysuper

再执行:

>>> a.super
<property at 0x1039fb778>

仅仅是返回一个 property 对象,而不会真正调用。这就是不能为类的实例增加 property 属性。

手机打字,不太方便,还请谅解

一个是
A.power = propertypower
a.power
9
另一个是
a.super = propertysuper
a.super
<property 0x1039fb778>

前一个成立,后一个不行

前面有点错误,感谢doukelung指出,已修改。

前面提问是在手机上写的,可能没讲清楚,回来专门重新做了个例子:

# 这里以一个记录有关教师和学生信息的类为例:
# 类中保存的信息有四项:姓名、身份、出生日期、学号/教职工编号、其中学号的内容是根据出生日期加
# 前缀2015生成的,教职工编号则根据出生日期加J2115前缀生成。出于演示的目的,姓名我使用实例变量的形式。身份和出生日期我使用类变量的形式,而编号则用property属性的方式来实现。
# 以下是代码:

class personobject:

    position = None  # 字符串如teacher/student
    birthday = None  # 字符串如19900512,1990年5月12日

    def __init__self,name,position,birthday:
        self.name = name # 实例变量
        self.position = position # 也是实例变量,但是在类中定义的,所以可以在
        self.birthday = birthday # person.__dict__中查到,当然每个实例中都
                                 # 有一个独立的copy。

    @property        # property 属性
    def idself:
        if self.position == teacher: return J2115+self.birthday
        if self.position == student: return 2015+self.birthday


tom = persontom,student,19990321
jim = personjim ,teacher,19770802

printname:%s\nposition:%s\nbirthday:%s\nid:%s%tom.name,tom.position,
                                                  tom.birthday,tom.id
printname:%s\nposition:%s\nbirthday:%s\nid:%s%jim.name,jim.position,
                                                  jim.birthday,jim.id

#######################################################################
# 运行结果:
name:tom
position:student
birthday:19990321
id:201519990321
name:jim 
position:teacher
birthday:19770802
id:J211519770802


# 如果我为person增加一个property属性,那么所有实例都能访问这个新的property属性

def olderself:
    return True if intself.birthday[0:4] < 1980 else False

person.older = propertyolder


>>>tom.older
False
>>>jim.older
True

# 如果我希望为tom增加一个此对象独有的变量,只能用基本的实例变量形式

>>>tom.livein = Beijing

>>>tom.livein
Beijing

>>>jim.livein
AttributeError: person object has no attribute livein

# 对象jim并没有livein这个变量

# 如果我以property的形式为tom增加一个属性

def sexself:
    return female if self.name in [mary,linda,jean] else male

tom.sex = propertysex

>>>tom.sex
<property at 0x103a07728>

# 它并不会执行sex函数,这就是说property只能赋予类域才起效果
# 我的问题就是有没有办法让它对实例对象也能有效
1

不好意思, 不太理解你想要做到的事情, 可以貼個示意的代碼嗎? 比如說這個功能實現的話, 你就可以怎麼操作實例了之類的

dokelung · 2016年07月24日

展开评论

首先,建议题主看一下python描述其引导这一章节:http://pyzh.readthedocs.io/en...

“默认对属性的访问控制是从对象的字典里面__dict__中获取get, 设置set和删除delete它。举例来说, a.x 的查找顺序是, a.__dict__[x] , 然后 typea.__dict__[x] , 然后找 typea 的父类不包括元类metaclass.”

在A实例化之后:
a.super = propertysuper
dira
[__class__, __delattr__, __dict__, __doc__, __format__, __getattribute__, __hash__, __init__, __module__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__, __weakref__, _x, getx, setx, super, x]
a.__dict__
{super: <property object at 0x1092ece68>, _x: 0}
请看a的__dict__中包含了什么,在a.super时,首先查找的是__dict__中是否包含了super,如果有则优先返回字典中的对象,也就是property。

ps:能告诉我你想实现基于类实例的动态property的目的吗? 因为类实例的对象你可以随意修改啊,为什么还需要property这个属性去做?

是的。
首先明确一点,给类增加property成员x时,实例中并没有x,
当你调用实例成员变量时,才调用类的property成员去计算值,
而直接给实例添加property成员的话,调用成员变量则是直接访问property成员。

说起来……如果两个实例可访问的成员不同……这其实就是两个类啊……

硬要实现的话,可以动态的在实例中增加一个变量__insproperty__,把属性加到这个变量里,然后实现/装饰类中的__getattr__方法,在__insproperty__查找,找到的话调用该属性的__get__方法……

栏目列表

广告位

澳门新葡京官网