文章目录
- 前言
- [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._dog.xxx
但是通过__getattr__这个魔法方法,和python的语法特性,实现了这个复合使用,这个在框架中非常常见,原理如果不理解,非常容易就让你模糊。