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

使用 @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: 클래스 인스턴스 기반의 동적 속성으로 무엇을 달성하고 싶은지 알려주실 수 있나요? 클래스 인스턴스의 객체를 마음대로 수정할 수 있는데 이를 위해 속성 속성이 필요한 이유는 무엇입니까?

黄舟

그렇습니다.
먼저 클래스에 속성 멤버 x를 추가하면 인스턴스에 x가 없다는 점을 분명히 하세요.
인스턴스 멤버 변수를 호출하면 클래스의 속성 멤버가 됩니다. 값을 계산하기 위해 호출됩니다. 인스턴스에 속성 멤버를 추가하면 멤버 변수를 호출하면 속성 멤버에 직접 액세스됩니다.

그러니까... 두 인스턴스의 액세스 가능한 멤버가 다르다면... 실제로는 두 클래스입니다...

구현을 고집하는 경우 인스턴스에 __insproperty__ 변수를 동적으로 추가하고 이 변수에 속성을 추가한 다음 클래스에서 __getattr__ 메서드를 구현/장식하고 __insproperty__에서 검색하여 발견되면 호출할 수 있습니다. 속성의...

최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿