__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的语法特性,实现了这个复合使用,这个在框架中非常常见,原理如果不理解,非常容易就让你模糊。

相关推荐
全栈弄潮儿2 小时前
Python实战第2期: 变量与数据类型
后端·python·agent
长沙三为智能科技2 小时前
家政小程序门店运营模块设计:会员、下单、派单、结算四段链路的落地拆解
python·小程序·内容运营
Cc.Y2 小时前
Java零基础入门:可变字符串与包装类:StringBuilder、StringBuffer 与 通讯录管理系统实战
java·开发语言·python
启观川2 小时前
数据结构与算法 -第 3 章 常用算法-动态规划
数据结构·笔记·python·算法
码爸2 小时前
排序算法介绍
python·算法·排序算法
笔墨登场说说3 小时前
flink bin/start-cluster.sh 帮我做成开机启动
开发语言·python
MoRanzhi12034 小时前
第 3 篇 · 数据清洗与特征工程:从问题判定到特征构建
python·pandas·数据清洗·特征工程·缺失值处理·异常值检测·特征编码
刘科领4 小时前
使用ollama & openweb-ui 本地搭建自己的AI
人工智能·python·ui·ai
专业程序开发源4 小时前
flask家电故障预测系统92491-计算机课程设计/毕业设计
vscode·python·sql·算法·flask·课程设计