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

使用 @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讲师

全員に返信(2)
阿神

まず、被験者は Python のガイダンスについて説明した章を参照することをお勧めします: http://pyzh.readthedocs.io/en...

「属性のデフォルトのアクセス制御は、オブジェクトの辞書 (__dict__) から属性を取得 (get)、設定 (set)、および削除 (delete) します。たとえば、 a.x の検索順序は、 a です。 __dict__['x']、次に type(a).__dict__['x']、そして type(a) の親クラスを見つけます (メタクラスを除く)。"

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': <0x1092ece68 のプロパティ オブジェクト> '_x': 0}
a の __dict__ に何が含まれているかを確認してください。a.super を使用する場合、最初に __dict__ に super が含まれているかどうかを確認します。含まれている場合は、辞書が最初に返されます。のオブジェクトがプロパティです。

ps: クラス インスタンスに基づく動的プロパティで何を実現したいのか教えていただけますか? クラス インスタンス オブジェクトは自由に変更できるのに、そのためにはなぜ property 属性が必要なのでしょうか?

いいねを押す +0
黄舟

はい。
まず、プロパティ メンバー x をクラスに追加するとき、インスタンスには x が存在しないことを明確にしてください。
インスタンス メンバー変数、つまりクラスのプロパティ メンバーを呼び出すとき。プロパティ メンバーをインスタンスに追加する場合、メンバー変数を呼び出すと、プロパティ メンバーに直接アクセスできます。

そういえば...2 つのインスタンスのアクセス可能なメンバーが異なる場合...これらは実際には 2 つのクラスです...

どうしても実装したい場合は、変数 __insproperty__ をインスタンスに動的に追加し、この変数に属性を追加してから、クラス内で __getattr__ メソッドを実装/装飾し、__insproperty__ 内を検索して、見つかった場合は呼び出します。 __get__ メソッド属性の...

いいねを押す +0
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート