小甲鱼零基础学习python_28 【python中魔法方法三:属性访问】

今天介绍以下四个访问属性的魔法方法:

    __getattribute__(self, item): 
    __getattr__(self, item):
    __setattr__(self, key, value):
    __delattr__(self, item):

小甲鱼零基础学习python_28 【python中魔法方法三:属性访问】_第1张图片

先定义一个类用来做实验:

class C:
    def __getattribute__(self, item):  
        print('getattribute')
        return super().__getattribute__(item)   #默认继承object类
    def __getattr__(self, item):
        print('getattr')
    def __setattr__(self, key, value):
        print('setattr')
        super().__setattr__(key,value)
    def __delattr__(self, item):
        print('delattr')
        super().__delattr__(item)

1. 若访问一个不存在的属性时:

c1=C()
print(c1.x)

小甲鱼零基础学习python_28 【python中魔法方法三:属性访问】_第2张图片

获取不存在属性的时候:getattribute比getattr先调用

先通过getattribute查找属性→找不到属性的时候采用getattr

2. 若访问一个存在的属性时:

c1.x=1
print(c1.x)

这里写图片描述

获取存在属性的时候:仅调用getattribute方法

3. 删除一个属性:

del c1.x

这里写图片描述


4. 用一个例子引入:死循环陷阱 → 矩形类:

#死循环陷阱  -- 矩形类例子

class Rectangle():
    def __init__(self, w=0, h=0):
        self.width=w
        self.height=h
    def __setattr__(self, name, value):
        if name=='square':
            self.width=value
            self.height=value
        else:
            self.name=value   #无限递归__setattr__,会错误  无限次调用本类的赋值方法
    def getArea(self):
        return self.width*self.height




r1=Rectangle(4,5)
print(r1.getArea())

r1.square=10
print(r1.getArea())
print(r1.__dict__)

r1.width=5   #尝试只改变width属性
print(r1.getArea())
print(r1.__dict__)

小甲鱼零基础学习python_28 【python中魔法方法三:属性访问】_第3张图片

错误原因:无限递归本类的_ _ setattr _ _,会错误 无限次调用本类的赋值方法;

解决办法1:调用基类方法(※推荐)

class Rectangle():
    def __init__(self, w=0, h=0):
        self.width=w
        self.height=h
    def __setattr__(self, name, value):
        if name=='square':
            self.width=value
            self.height=value
        else:
            super().__setattr__(name,value)   #推荐:方法一:调用基类方法

    def getArea(self):
        return self.width*self.height


r1=Rectangle(4,5)
print(r1.getArea())

r1.square=10
print(r1.getArea())
print(r1.__dict__)

r1.width=5   #尝试只改变width属性
print(r1.getArea())
print(r1.__dict__)

小甲鱼零基础学习python_28 【python中魔法方法三:属性访问】_第4张图片

解决办法2:利用字典改变


class Rectangle():
    def __init__(self, w=0, h=0):
        self.width=w
        self.height=h
    def __setattr__(self, name, value):
        if name=='square':
            self.width=value
            self.height=value
        else:
            self.__dict__[name] = value   #方法二:利用字典改变
    def getArea(self):
        return self.width*self.height

r1=Rectangle(4,5)
print(r1.getArea())

r1.square=10
print(r1.getArea())
print(r1.__dict__)

r1.width=5      #尝试只改变width属性
print(r1.getArea())
print(r1.__dict__)

小甲鱼零基础学习python_28 【python中魔法方法三:属性访问】_第5张图片


补充: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 deleteSize(self):
        del self.size
    x=property(getSize,setSize,deleteSize)

1. 赋值操作:

c1.x=100

2. 访问操作:

print(c1.x)

3. 删除操作:

del c1.x

其中x和size挂钩,改变或者删除x,size也随之改变或者删除!

你可能感兴趣的:(Python,note)