Home  >  Q&A  >  body text

Python 中基于实例对象的动态property就真的无法实现吗?

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

举例:

class A(object):
    var = 2

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

A.var = 3 或 print(A.var)

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

def power(self): return self.var**2

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

A.power = property(power)

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

a=A()
>>> a.power
9

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

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

a = A()
def super(self):
    return self.var**3
a.super = property(super)

再执行:

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

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

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

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

前一个成立,后一个不行

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

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

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

class person(object):

    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 id(self):
        if self.position == 'teacher': return 'J2115'+self.birthday
        if self.position == 'student': return '2015'+self.birthday


tom = person('tom','student','19990321')
jim = person('jim ','teacher','19770802')

print('name:%s\nposition:%s\nbirthday:%s\nid:%s'%(tom.name,tom.position,
                                                  tom.birthday,tom.id))
print('name:%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 older(self):
    return True if int(self.birthday[0:4]) < 1980 else False

person.older = property(older)


>>>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 sex(self):
    return 'female' if self.name in ['mary','linda','jean'] else 'male'

tom.sex = property(sex)

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

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

reply all(2)I'll reply

  • 阿神

    阿神2017-04-18 09:18:01

    First of all, it is recommended that the subject take a look at the chapter where python describes its guidance: http://pyzh.readthedocs.io/en...

    "The default access control for attributes is to get (get), set (set) and delete (delete) it from the object's dictionary (__dict__). For example, the search order for a.x is, a.__dict__[' x'], then type(a).__dict__['x'], then find the parent class of type(a) (excluding metaclass)."

    After A is instantiated:
    a.super = property(super)
    dir(a)
    ['__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}
    Please see a's __dict__ What is contained in a.super? The first thing to look for is whether __dict__ contains super. If so, the object in the dictionary, that is, property, will be returned first.

    ps: Can you tell me what you want to achieve with dynamic properties based on class instances? Because you can modify the object of the class instance at will, why do you need the property attribute to do it?

    reply
    0
  • 黄舟

    黄舟2017-04-18 09:18:01

    Yes.
    First of all, make it clear that when you add a property member x to a class, there is no Member variables directly access the property member.

    Speaking of which...if the accessible members of two instances are different...this is actually two classes...

    If you insist on implementing it, you can dynamically add a variable __insproperty__ to the instance, add the attribute to this variable, then implement/decorate the __getattr__ method in the class, search in __insproperty__, and call the attribute if found __get__ method……

    reply
    0
  • Cancelreply