python的元类编程

这篇文章我们将会了解到类的整个实例化过程。

property动态属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from datetime import date, datetime
class User:
def __init__(self, name, birthday):
self.name = name
self.birthday = birthday

@property
def age(self):
return self._age

@age.setter
def age(self, value):
self._age = value


if __name__ == "__main__":
user = User("hongshaorou", date(year=1992, month=1, day=1))
user.age = 26
print(user.age)

@property装饰器负责把一个方法变成属性调用。 把一个getter方法变成属性,只需要加上@property就可以了,此时@property本身又创建了另一个装饰器@age.setter,负责把一个setter方法变成属性赋值。

参考文章:http://python.jobbole.com/80955/

___getattr____getattribute__的区别

___getattr__是在属性查找不到的时候进行的调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from datetime import date, datetime
class User:
def __init__(self, name, birthday):
self.name = name
self.birthday = birthday

def __getattr__(self, item):
return "not find"

if __name__ == "__main__":
user = User("hongshaorou", date(year=1992, month=1, day=1))
print(user.age)
# 输出
not find

这样我们就可以在查找不到的时候做一些操作。

1
2
3
4
5
6
7
8
9
10
11
from datetime import date
class User:
def __init__(self,info={}):
self.info = info

def __getattr__(self, item):
return self.info[item]

if __name__ == "__main__":
user = User(info={"name":"hongshaorou"})
print(user.name)

上面代码我们虽然没有设置name属性,按时info里面有,我们通过这种操作完成了查询、

__getattribute__是在查询任何属性的时候都调用

__getattribute__是非常可怕的,无论属性是否存在在查找的时候都会调用,不建议使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class User:
def __init__(self, info={}):
self.info = info

def __getattribute__(self, item):
return "hongshaorou"


if __name__ == "__main__":
user = User(info={"name": "hongshaorou"})
print(user.age)

# 输出
hongshaorou

属性描述符和属性查找过程

描述符是对多个属性运用相同存取逻辑的一种方式。例如,Django ORM 和 SQL Alchemy
等 ORM 中的字段类型是描述符,把数据库记录中字段里的数据与 Python 对象的属性对应
起来。
描述符是实现了特定协议的类,这个协议包括 __get____set____delete__
法。property 类实现了完整的描述符协议。通常,可以只实现部分协议。其实,我们在
真实的代码中见到的大多数描述符只实现了 __get____set__方法,还有很多只实现
了其中的一个。

描述符是 Python 的独有特征,不仅在应用层中使用,在语言的基础设施中也有用到。除
了特性之外,使用描述符的 Python 功能还有方法及 classmethod 和 staticmethod 装饰
器。理解描述符是精通 Python 的关键。本章的话题就是描述符。

实现了 __get____set____delete__ 方法的类是描述符。描述符的用法是,创建
一个实例,作为另一个类的类属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import numbers
'''
如果user是某个类的实例,那么user.age(以及等价的getattr(user,’age’))
首先调用__getattribute__。如果类定义了__getattr__方法,
那么在__getattribute__抛出 AttributeError 的时候就会调用到__getattr__,
而对于描述符(__get__)的调用,则是发生在__getattribute__内部的。
user = User(), 那么user.age 顺序如下:

(1)如果“age”是出现在User或其基类的__dict__中, 且age是data descriptor, 那么调用其__get__方法, 否则

(2)如果“age”出现在user的__dict__中, 那么直接返回 obj.__dict__[‘age’], 否则

(3)如果“age”出现在User或其基类的__dict__中

(3.1)如果age是non-data descriptor,那么调用其__get__方法, 否则

(3.2)返回 __dict__[‘age’]

(4)如果User有__getattr__方法,调用__getattr__方法,否则

(5)抛出AttributeError

'''
class IntField:
"""数据描述符"""
def __get__(self, instance, owner):
return self.value

def __set__(self, instance, value):
if isinstance(value,numbers.Integral):
self.value = value
else:
raise ValueError

def __delete__(self, instance):
pass

class NotIntField:
"""非数据描述"""
def __get__(self, instance, owner):
return 31

class User:
age = IntField()
# age = NotIntField()

def __init__(self,name,weight):
self.name = name
self.weight = weight

user = User("zhou",34)
user.age = 10
print(user.__dict__)
print("User.__dict__: ", User.__dict__)
print("IntField.__dict__: ", IntField.__dict__)
print(user.age)
知识就是财富
如果您觉得文章对您有帮助, 欢迎请我喝杯水!