Rumah  >  Soal Jawab  >  teks badan

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 hari yang lalu303

membalas semua(2)saya akan balas

  • 阿神

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

    Pertama sekali, adalah disyorkan agar subjek melihat bab yang menerangkan panduan python: http://pyzh.readthedocs.io/en...

    "Kawalan akses lalai untuk atribut adalah untuk mendapatkan (mendapat), menetapkan (menetapkan) dan memadam (memadam)nya daripada kamus objek (__dict__). Contohnya, susunan carian a.x ialah, a . __dict__['x'], kemudian taip(a).__dict__['x'], dan kemudian cari kelas induk jenis(a) (tidak termasuk metaclass)."

    Selepas A disegerakan:
    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': <objek harta di 0x1092ece68> , '_x': 0}
    Sila lihat apa yang terkandung dalam __dict__ a. Apabila a.super digunakan, perkara pertama yang perlu diperiksa ialah sama ada __dict__ mengandungi super. Objek dalam ialah harta.

    ps: Bolehkah anda beritahu saya apa yang anda mahu capai dengan sifat dinamik berdasarkan kejadian kelas? Kerana anda boleh mengubah suai objek contoh kelas sesuka hati, mengapa anda memerlukan atribut sifat untuk melakukannya?

    balas
    0
  • 黄舟

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

    Ya.
    Pertama sekali, jelaskan bahawa apabila anda menambahkan ahli sifat x pada kelas, tiada x dalam tika itu
    Apabila anda memanggil pembolehubah ahli instance, ahli sifat kelas dipanggil untuk mengira nilai Jika anda menambah ahli harta pada contoh, memanggil pembolehubah ahli secara langsung mengakses ahli harta.

    Bercakap mengenainya... jika ahli yang boleh diakses daripada dua kejadian adalah berbeza... ini sebenarnya dua kelas...

    Jika anda berkeras untuk melaksanakannya, anda boleh menambah pembolehubah __insproperty__ secara dinamik pada contoh, tambah atribut pada pembolehubah ini, kemudian laksanakan/hias kaedah __getattr__ dalam kelas, cari dalam __insproperty__ dan panggilnya jika ditemui Kaedah __get__ daripada sifat...

    balas
    0
  • Batalbalas