__getattr__和__getattribute__如何用

文章目录

  • 前言
  • [getattr 用法](#getattr 用法)
  • __getattribute__方法
  • [object 中定义的__getattribute__](#object 中定义的__getattribute__)

前言

django的动态性之所以这么好,多亏了内置魔法方法的支持,比如__getattr__, getattribute

getattr 用法

在当前对象的类定义中,没有找到的属性或者方法,会执行类中的__getattr__方法

比如:

python 复制代码
class Animal(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self):
        print("play...")

    def sleep(self):
        print('sleep...')

    def __getattr__(self, attr):
        print('__getattr__', attr)
        return attr


def main():
    a = Animal("tide", 11)
    print(a.name)
    a.eat()
    a.sleep()
    


if __name__ == '__main__':
    main()

定义一个动物类,获取已经定义的属性,name和age, 是不经过__getattr__方法的

调用eat. sleep 方法 也是不经过__getattr__方法的

python 复制代码
def main():
    a = Animal("tide", 11)
    # print(a.name)
    # a.eat()
    # a.sleep()
    print(a.gender)
    a.play()

比如再去调用对象中没有的属性,和不存在的方法

返回如下:

shell 复制代码
__getattr__ gender
gender
__getattr__ play
Traceback (most recent call last):
  File "D:\code_workspace\learn_django\test_group\learn_oop.py", line 31, in <module>
    main()
    ~~~~^^
  File "D:\code_workspace\learn_django\test_group\learn_oop.py", line 26, in main
    a.play()
    ~~~~~~^^
TypeError: 'str' object is not callable

这个时候你会发现,在调用该类不存在的属性的时候会触发__getattr__方法,并且会把__getattr__方法的返回值给到这个属性或者方法。

从我的示例代码中可以发现,我只是把属性名称一个字符串类型的值返回了回来,再去调用的过程中,显然报错了,因为字符串不能再去加一个括号执行调用,只有方法,函数等是callable的。

__getattribute__方法

python 复制代码
class Animal(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self):
        print("play...")

    def sleep(self):
        print('sleep...')

    def __getattr__(self, attr):
        print('__getattr__', attr)
        return attr

    def __getattribute__(self, name: str, /) -> Any:
        print('__getattribute__', name)

调用函数:

python 复制代码
def main():
    a = Animal("tide", 11)
    print(a.name)

返回值:

python 复制代码
__getattribute__ name
None

调用函数:

python 复制代码
def main():
    a = Animal("tide", 11)
    print(a.xxx)

返回值:

python 复制代码
__getattribute__ xxx
None

从结果可以发现,不管你定义的类有无该属性,都经过了__getattribute__

但是我们自己定义的__getattribute__方法没有设置返回值,所以,当然访问任何属性都是None。

给方法增加一个return 返回值

python 复制代码
class Animal(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self):
        print("play...")

    def sleep(self):
        print('sleep...')

    def __getattr__(self, attr):
        print('__getattr__', attr)
        return attr

    def __getattribute__(self, name: str, /) -> Any:
        print('__getattribute__', name)
        return name+'xxx'

执行函数:

python 复制代码
def main():
    a = Animal("tide", 11)
    print(a.name)
    print(a.xxx)

返回值:

复制代码
__getattribute__ name
namexxx
__getattribute__ xxx
xxxxxx

object 中定义的__getattribute__

object 类是所有类的基类,所有的类都是继承于object类

python 复制代码
class Dog(object):
    def __init__(self, xxx):
        self.xxx = xxx

    def kanmengou(self):
        print('kanmengou')


class Animal(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self._dog = Dog('我是一只看门狗')

    def eat(self):
        print("play...")

    def sleep(self):
        print('sleep...')

    def __getattr__(self, attr):
        try:
            return getattr(self._dog, attr)
        except AttributeError:
            return super().__getattribute__(attr)


    def __getattribute__(self, name: str, /) -> Any:
        print('__getattribute__', name)
        return super().__getattribute__(name)


def main():
    a = Animal("tide", 11)
    print(a.name)
    print(a.xxx)

这个__getattr__特别适合做这种伪装

a 实际是Animal 对象,但是当访问a.xxx时候,因为Animal类中没有,所以需要去__getattr__中,__getattr__中定义了去Dog类中查找这个属性,如果找不到的话就抛出异常,实际上

a.xxx

调用的是

a._dog.xxx

但是通过__getattr__这个魔法方法,和python的语法特性,实现了这个复合使用,这个在框架中非常常见,原理如果不理解,非常容易就让你模糊。

相关推荐
第九序言T7 小时前
Python 数据处理进阶(十八)批量处理同结构文件:一个文件夹一次跑完
开发语言·python·自动化·pandas·数据处理
Java后端的Ai之路7 小时前
CAS并发控制-从CPU指令到企业级乐观锁
vue.js·人工智能·python·cas·乐观锁
qq_426003967 小时前
UI自动化高频次登录login限流解决方案
python·ui·自动化
Sakura_j_h_8 小时前
EasyEDA PCB 快速设计Skills
c++·python·github
quantdash_cc9 小时前
如何验证历史行情的交易日期是否完整覆盖研究区间?
python·数据分析·pandas·量化交易·股票数据·quantdash
I Am a robert girl9 小时前
当智能体学会“串通”:从长程交互中读懂涌现式合谋
python·多智能体系统·多智能体协作·llm agent·涌现式合谋·对齐问题·激励机制设计
云和数据.ChenGuang10 小时前
光哥说Python RAG 系统需要哪些评估指标:从检索到生成的全链路评测指南
网络·人工智能·python·算法·langchain
专注仿真10 小时前
线性回归和逻辑回归算法详解
开发语言·人工智能·python·大模型训练·控制算法
wflynn11 小时前
GitHub 今日推荐|Edge0:让大号 MoE 模型在一台 Mac 上流式跑起来
python·开源·github
2601_9679801111 小时前
python之用scapy分层解析pcap报文(Ethernet帧、IP数据包、TCP数据包、UDP数据包、Raw数据包)
python·scapy·pcap·协议分析·网络数据包