微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

课时45:魔法方法:属性访问

目录:

  一、属性访问

  二、课时45课后习题及答案

 

****************

一、属性访问

****************

 通常可以通过(.)操作符的形式去访问对象的属性,在类与对象这一章的最后一节也有谈到如何通过几个BIF适当地去访问属性

>>> class C:
    def __init__(self):
        self.x = X-man

        
>>> c = C()
>>> c.x
X-man
>>> getattr(c,x,木有这个属性)
X-man
>>> getattr(c,y,木有这个属性)
木有这个属性
>>> setattr(c,Yellow)
>>> getattr(c,木有这个属性)
Yellow
>>> delattr(c,x)
>>> c.x
Traceback (most recent call last):
  File "<pyshell#11>",line 1,in <module>
    c.x
AttributeError: C object has no attribute x

然后还介绍了一个叫做property()函数用法,这个property()使得我们可以用属性去访问属性

>>> class C:
    def __init__(self,size = 10):
        self.size = size
    def getSize(self):
        return self.size
    def setSize(self,value):
        self.size = value
    def delSize(self):
        del self.size
    x = property(getSize,setSize,delSize)

    
>>> c = C()
>>> c.x
10
>>> c.x = 12
>>> c.x
12
>>> c.size
12
>>> del c.x
>>> c.size
Traceback (most recent call last):
  File "<pyshell#29>",in <module>
    c.size
AttributeError: C object has no attribute size

那么关于属性访问,肯定也有相应得魔法方法来管理。通过对这些魔法方法的重写,可以随心所欲的控制对象的属性访问。

下表列举了属性相关的魔法方法

__getattr__(self,name)             定义当用户试图获取一个不存在的属性时的行为
__getattribute__(self,name)       定义当该类的属性被访问时的行为
__setattr__(self,name,value)     定义当一个属性被设置时的行为
__delattr__(self,name)             定义当一个属性删除时的行为

做个小测试:

class C:
    def __getattribute__(self,name):
        print(getattribute)
        # 使用 super() 调用 object 基类的 __getattribute__ 方法
        return super().__getattribute__(name)

    def __setattr__(self,value):
        print(setattr)
        super().__setattr__(name,value)

    def __delattr__(self,name):
        print(delattr)
        super().__delattr__(name)

    def __getattr__(self,name):
        print(getattr)
>>> c = C()
>>> c.x
getattribute
getattr
>>> c.x = 1
setattr
>>> c.x
getattribute
1
>>> del c.x
delattr
>>> setattr(c,Yellow)
setattr

这几个魔法方法在使用上需要注意的是,有一个死循环的陷阱,初学者很容易中招,通过一个实例来讲解。

一个矩形类,认有宽和高两个属性
如果为一个叫square的属性赋值,那么说明这是一个正方形,值就是正方形的边长,此时宽和高都应该等于边长。

class Rectangle:
    def __init__(self,width=0,height=0):
        self.width = width
        self.height = height

    def __setattr__(self,value):
        if name == square:
            self.width = value
            self.height = value
        else:
            self.name = value

    def getArea(self):
        return self.width * self.height
>>> r1 = Rectangle(4,5)
Traceback (most recent call last):
  File "<pyshell#0>",in <module>
    r1 = Rectangle(4,5)
  File "C:\Users\14158\Desktop\lalallalalal.py",line 3,in __init__
    self.width = width
  File "C:\Users\14158\Desktop\lalallalalal.py",line 11,in __setattr__
    self.name = value
  File "C:\Users\14158\Desktop\lalallalalal.py",in __setattr__
    self.name = value
  [PrevIoUs line repeated 987 more times]
  File "C:\Users\14158\Desktop\lalallalalal.py",line 7,in __setattr__
    if name == square:
RecursionError: maximum recursion depth exceeded in comparison

这是为什么呢?

分析一下:实例化对象,调用__init__()方法在这里self.width和self.heigth分别初始化赋值。一发生赋值操作,就会自动触发__setattr__()魔法方法,width和height两个属性被赋值,于是执行else的下边的语句,就变成了self.width = value,那么就相当于又触发了__setattr__(),那么这样就依赖基类的方法来实现赋值:

        else:
            super().__setattr__(name,value)
>>> r1 = Rectangle(4,5)
>>> r1.getArea()
20
>>> r1.square = 10
>>> r1.getArea()
100

另一种方法就是给特殊属性__dict__赋值。对象有一个特殊属性,叫做__dict__,它的作用是以字典的形式显示出当前对象的所有属性以及相对应的值:

        else:
            self.__dict__[name] = value

运行结果一样。

 

*******************************

二、课时45课后习题及答案

*******************************

 

分享图片

分享图片

分享图片

分享图片

分享图片

分享图片

分享图片

分享图片

分享图片

分享图片

分享图片

分享图片

分享图片

分享图片

分享图片

分享图片

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐