python 3.x 元类编程(property,__getattr__,__getattribute__)

元类编程

property动态属性

  • property将函数变成一个属性描述符
  • 给函数添加一个@property装饰器,就可以通过获取属性的模式来获取函数.(user.age --> user.age())
 1 from datetime import date, datetime
 2 
 3 
 4 class User:
 5     def __init__(self, name, birthday):
 6         self.name = name
 7         self.birthday = birthday
 8 
 9     def get_age(self):
10         """获取现在的年龄"""
11         return datetime.now().year - self.birthday.year
12 
13 
14 if __name__ == '__main__':
15     user = User('python', date(1988, 3, 1))
16 
17     # 结果: 31  (2019 - 1988 = 31)
18     print(user.get_age())

 

 

 1 """
 2 property动态属性
 3 
 4     假设如果存在一个这样的应用场景:
 5         比如之前在创建数据库的时候设置一个age的字段,但后期删除age这个字段,删除数据库的字段很正常.
 6         但是之前有大量的获取年龄的语句都是以user.age的形式获取.现在如果使用函数的方式来获取年龄.
 7         那么之前user.age语句都要修改为调用函数的方式get_age().
 8 
 9         这样的话修改代码量非常的大.有没有什么方法不修该原来的user.age代码,同时还可以获取age年龄???
10 
11         这就涉及到python的计算属性@property装饰器
12         property将age函数变成一个属性描述符
13         给函数添加一个@property装饰器,就可以通过获取属性的模式来获取函数.(user.age --> user.age())
14 """
15 from datetime import date, datetime
16 
17 
18 class User:
19     def __init__(self, name, birthday):
20         self.name = name
21         self.birthday = birthday
22         # self.age = 0
23 
24     # def get_age(self):
25     #     """获取现在的年龄"""
26     #     return datetime.now().year - self.birthday.year
27 
28     @property
29     def age(self):
30         return datetime.now().year - self.birthday.year
31 
32 
33 if __name__ == '__main__':
34     user = User('python', date(1988, 3, 1))
35     # 结果: 31  (2019 - 1988 = 31)
36     print(user.age)

 

 

 1 """
 2 property动态属性
 3 
 4     假设如果存在一个这样的应用场景:
 5         比如之前在创建数据库的时候设置一个age的字段,但后期删除age这个字段,删除数据库的字段很正常.
 6         但是之前有大量的获取年龄的语句都是以user.age的形式获取.现在如果使用函数的方式来获取年龄.
 7         那么之前user.age语句都要修改为调用函数的方式get_age().
 8 
 9         这样的话修改代码量非常的大.有没有什么方法不修该原来的user.age代码,同时还可以获取age年龄???
10 
11         这就涉及到python的计算属性@property装饰器
12         property将age函数变成一个属性描述符
13         给函数添加一个@property装饰器,就可以通过获取属性的模式来获取函数.(user.age --> 函数def age(self))
14 
15     设置@property装饰器修饰的函数的值,需要装饰器@function_name.setter
16     代码书写规范使用@function_name.setter装饰器时,需要设置属性的变量名前添加单一下划线.如_age,_birthday
17 """
18 from datetime import date, datetime
19 
20 
21 class User:
22     def __init__(self, name, birthday):
23         self.name = name
24         self.birthday = birthday
25         self._age = 0
26 
27     @property
28     def age(self):
29         return datetime.now().year - self.birthday.year
30 
31     @age.setter
32     def age(self, value):
33         self._age = value
34 
35 
36 if __name__ == '__main__':
37     user = User('python', date(1988, 3, 1))
38     user.age = 18
39     # 结果: 18
40     print(user._age)
41     # 结果: 31
42     print(user.age)

 

 

 1 """
 2 property动态属性
 3 
 4     假设如果存在一个这样的应用场景:
 5         比如之前在创建数据库的时候设置一个age的字段,但后期删除age这个字段,删除数据库的字段很正常.
 6         但是之前有大量的获取年龄的语句都是以user.age的形式获取.现在如果使用函数的方式来获取年龄.
 7         那么之前user.age语句都要修改为调用函数的方式get_age().
 8 
 9         这样的话修改代码量非常的大.有没有什么方法不修该原来的user.age代码,同时还可以获取age年龄???
10 
11         这就涉及到python的计算属性@property装饰器
12         property将age函数变成一个属性描述符
13         给函数添加一个@property装饰器,就可以通过获取属性的模式来获取函数.(user.age --> 函数def age(self))
14 
15     设置@property装饰器修饰的函数的值,需要装饰器@function_name.setter
16     代码书写规范使用@function_name.setter装饰器时,需要设置属性的变量名前添加单一下划线.如_age,_birthday
17 """
18 from datetime import date, datetime
19 
20 
21 class User:
22     def __init__(self, name, birthday):
23         self.name = name
24         self._birthday = birthday
25         self._age = 0
26 
27     @property
28     def age(self):
29         return datetime.now().year - self._birthday.year
30 
31     @age.setter
32     def age(self, value):
33         self._birthday = value
34 
35 
36 if __name__ == '__main__':
37     user = User('python', date(1988, 3, 1))
38     user.age = date(2016, 2, 2)
39     # 结果: 2016-02-02
40     print(user._birthday)
41     # 结果: 3
42     print(user.age)
43     # 结果: 0
44     print(user._age)

 

 

__getattr__()与__getattribute__()魔法函数的区别

  • 类当中对属性操作的两个重要的魔法函数
  1. __getattr__(self, item)魔法函数,在查找不到属性的时候调用.
  2. __getattribute__(self,item)魔法函数在__getattr__()魔法函数先调用.在构造函数初始化属性时,无条件执行魔法函数(所以不要轻易的覆写__getattribute__()魔法函数.一但逻辑上处理不完善,会影响整个类的属性)
 1 """
 2 __getattr__()与__getattribute__()魔法函数的区别
 3     类当中对属性操作的两个重要的魔法函数
 4     __getattr__()魔法函数,在查找不到属性的时候调用.
 5 """
 6 from datetime import date
 7 
 8 
 9 class User:
10     def __init__(self, name, birthday):
11         self.name = name
12         self.birthday = birthday
13 
14 
15 if __name__ == '__main__':
16     user = User('python', date(1990, 10, 11))
17     # 当age属性在User类中不存在的时候调用age,没有覆写__getattr__()魔法函数.
18     # 报错: AttributeError: 'User' object has no attribute 'age'
19     print(user.age)

 

 

 1 """
 2 __getattr__()与__getattribute__()魔法函数的区别
 3     类当中对属性操作的两个重要的魔法函数
 4     __getattr__()魔法函数,在查找不到属性的时候调用.
 5 """
 6 from datetime import date
 7 
 8 
 9 class User:
10     def __init__(self, name, birthday):
11         self.name = name
12         self.birthday = birthday
13 
14     def __getattr__(self, item):
15         return 'not find attribute'
16 
17 
18 if __name__ == '__main__':
19     user = User('python', date(1990, 10, 11))
20     # 当age属性在User类中不存在的时候,去调用魔法函数__getattr__()将结果返回.
21     # 结果: not find attribute
22     print(user.age)

 

 

 1 """
 2 __getattr__()与__getattribute__()魔法函数的区别
 3     类当中对属性操作的两个重要的魔法函数
 4     __getattr__(self, item)魔法函数,在查找不到属性的时候调用.
 5 
 6     比如在User里面维护一个dict的类型的参数.我们在类的外部不使用user.dict[key]的形式来获取value.
 7     想通过user.key的形式来获取value.这时就需要调用__getattr__(self, item)魔法函数,在魔法函数内部实现自己的逻辑
 8 
 9 """
10 
11 
12 class User:
13     def __init__(self, infos):
14         self.infos = infos
15 
16     def __getattr__(self, item):
17         """
18         __getattr__(self, item)魔法函数,在查找不到属性的时候调用.
19         :param item: 获取指定的key
20         :return: value
21         """
22         return self.infos[item]
23 
24 
25 if __name__ == '__main__':
26     user = User(infos={'name': 'python', 'age': 18})
27     # 当age属性在User类中不存在的时候调用age,调用魔法函数__getattr__()
28     # 结果: python
29     print(user.name)
30     # 结果: 18
31     print(user.age)

 

 

 1 """
 2 __getattr__()与__getattribute__()魔法函数的区别
 3     类当中对属性操作的两个重要的魔法函数
 4     __getattr__(self, item)魔法函数,在查找不到属性的时候调用.
 5     __getattribute__(self,item)魔法函数在__getattr__()魔法函数前先调用.在构造函数初始化属性时,无条件执行的魔法函数
 6 """
 7 
 8 
 9 class User:
10     def __init__(self, infos):
11         self.infos = infos
12 
13     def __getattr__(self, item):
14         return user.infos[item]
15 
16     def __getattribute__(self, item):
17         return "__getattribute__"
18 
19 
20 if __name__ == '__main__':
21     user = User({'name': 'python', 'age': 18})
22     # 结果: __getattribute__
23     print(user.name)
24     # 结果: __getattribute__
25     print(user.age)
26 
27     """
28     通过以上的结果得出结论:
29         __getattribute__(self,item)魔法函数影响整个类的属性,稍有逻辑上处理不好,导致整个类的属性出现问题.
30         所以不要轻易的覆写__getattribute__(self,item)魔法函数.
31     """

 

 

 

 

 

 

 

 

 

 

********

posted on 2019-04-08 13:00  jaydenjune  阅读(48)  评论(0)    收藏  举报

导航