Python 中基于实例对象的动态property就真的无法实现吗?
PHP中文网
PHP中文网 2017-04-18 09:16:01
0
2
330

使用 @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中文网

认证高级PHP讲师

répondre à tous(2)
阿神

Tout d'abord, il est recommandé au sujet de jeter un oeil au chapitre décrivant le guidage de python : http://pyzh.readthedocs.io/en...

"Le contrôle d'accès par défaut pour les attributs consiste à les obtenir (obtenir), à définir (définir) et à supprimer (supprimer) du dictionnaire de l'objet (__dict__). Par exemple, l'ordre de recherche de a.x est a . __dict__['x'], puis tapez(a).__dict__['x'], puis recherchez la classe parent de type(a) (à l'exclusion de la métaclasse)."

Après l'instanciation de A :
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' : <objet de propriété à 0x1092ece68> '_x' : 0}
Veuillez voir ce qui est contenu dans __dict__ de a. Lorsque a.super est utilisé, la première chose à vérifier est si __dict__ contient super. Si c'est le cas, le dictionnaire sera renvoyé en premier. L'objet est la propriété.

ps : Pouvez-vous me dire ce que vous souhaitez réaliser avec des propriétés dynamiques basées sur des instances de classe ? Parce que vous pouvez modifier l'objet de l'instance de classe à volonté, pourquoi avez-vous besoin de l'attribut property pour le faire ?

黄舟

Oui.
Tout d'abord, précisez que lorsque vous ajoutez un membre de propriété x à une classe, il n'y a pas de x dans l'instance
Lorsque vous appelez la variable membre d'instance, le membre de propriété de la classe. est appelée pour calculer la valeur. Si vous ajoutez un membre de propriété à une instance, l'appel de la variable membre accède directement au membre de propriété.

En parlant de ça... si les membres accessibles de deux instances sont différents... ce sont en fait deux classes...

Si vous insistez pour l'implémenter, vous pouvez ajouter dynamiquement une variable __insproperty__ à l'instance, ajouter des attributs à cette variable, puis implémenter/décorer la méthode __getattr__ dans la classe, rechercher dans __insproperty__ et l'appeler si elle est trouvée. La méthode __get__ de l'attribut...

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal