设为首页 收藏本站
查看: 1338|回复: 0

[经验分享] Python:高级主题之(属性取值和赋值过程、属性描述符、装饰器)

[复制链接]

尚未签到

发表于 2015-4-21 07:40:44 | 显示全部楼层 |阅读模式
背景
  学习了Javascript才知道原来属性的取值和赋值操作访问的“位置”可能不同、还有词法作用域这个东西,这也是我学习任何一门语言会注意的两个知识点,Python的作用域和Javascript几乎一致,这里就不做解释,本文重点介绍一下三个概念:


  • 属性取值和赋值过程
  • 属性描述符
  • 装饰器
  本文最好会利用这些知识介绍:如何实现自定义的@staticmethod和@classmethod。

属性取值和赋值过程
DSC0000.jpg


  • 一切皆是对象,类型也是对象。
  • 对象包含一个__class__属性指向其所属类型。
  • 对象包含一个__dict__属性指向其所包含的成员(属性和方法)。

取值过程(下面是伪代码)



1 __getattribute__(property) logic:
2
3 descripter = find first descripter in class and bases's dict(property)
4 if descripter:
5     return descripter.__get__(instance, instance.__class__)
6 else:
7     if value in instance.__dict__
8         return value
9
10     value = find first value in class and bases's dict(property)
11     if value is a function:
12         return bounded function(value)
13     else:
14         return value
15
16 raise AttributeNotFundedException
赋值过程(下面是伪代码)



1 __setattr__(property, value)logic:
2
3 descripter = find first descripter in class and bases's dict(property)
4 if descripter:
5     descripter.__set__(instance, value)
6 else:
7     instance.__dict__[property] = value
根据取值和赋值过程的逻辑可以得出以下结论


  • 赋值和取值的位置可能不同。
  • 取值过程的伪代码第11行会返回绑定方法(我们在Javascript经常会让某个函数绑定到指定的作用域,和这个概念是一样的)。
  • 取值和赋值过程都会先查找属性描述符,也就是说:属性描述的优先级最高,下文会介绍属性描述符。

属性描述符
  什么是属性描述符?属性描述符就是一个类型,实现了三个魔法方法而已:__set__、__get__和__del__,属性描述符一般不会独立使用,必须存储在类型的__dict__中才有意义,这样才会参与到属性的取值和赋值过程,具体参见上文。
  属性描述符



1 #属性描述符
2 class Descripter:
3     def __get__(self, instance, owner):
4         print(self, instance, owner)
5
6     def __set__(self, instance, value):
7         print(self, instance, value)
  测试代码



1 class TestClass:
2     Des = Descripter()
3
4
5     def __getattribute__(self, name):
6         print("before __getattribute__")
7         return    super(TestClass, self).__getattribute__(name)
8         print("after __getattribute__")
9
10     def __setattr__(self, name, value):
11         print("before __setattr__")
12         super(TestClass, self).__setattr__(name, value)
13         print("after __setattr__")
14
15 test1 = TestClass()
16 test2 = TestClass()
17
18 test1.Des = None
19 test2.Des
  输出结果



1 before __setattr__
2   None
3 after __setattr__
4 before __getattribute__
5   
  结论
  类型的多个实例共享同一个属性描述符实例,属性描述符的优先级高于实例的__dict__,具体自己可以测试一下。

装饰器(AOP)
  最基本的函数装饰器



1 print("\n最基本的函数装饰器\n")
2 def log(fun):
3     def return_fun(*args, **kargs):
4         print("开始输出日志")
5
6         fun(*args, **kargs)
7
8         print("结束输出日志")
9
10     return return_fun
11
12 @log
13 def say(message):
14     print(message)
15
16 say("段光伟")
17
18 print("\n等价方法\n")
19
20 def say(message):
21     print(message)
22
23 say = log(say)
24 say("段光伟")
  带参数的函数装饰器



1 print("\n带参数的函数装饰器\n")
2 def log(header, footer):
3     def log_to_return(fun):
4         def return_fun(*args, **kargs):
5             print(header)
6
7             fun(*args, **kargs)
8
9             print(footer)
10
11         return return_fun
12     return log_to_return
13
14 @log("开始输出日志", "结束输出日志")
15 def say(message):
16     print(message)
17
18 say("段光伟")
19
20 print("\n等价方法\n")
21
22 def say(message):
23     print(message)
24
25 say = log("开始输出日志", "结束输出日志")(say)
26 say("段光伟")
  最基本的类型装饰器



1 print("\n最基本的类型装饰器\n")
2 def flyable(cls):
3     def fly(self):
4         print("我要飞的更高")
5     cls.fly = fly
6     
7     return cls
8
9 @flyable
10 class Man:
11     pass
12
13 man = Man()
14 man.fly()
15
16 print("\n等价方法\n")
17
18 class Man:
19     pass
20
21 Man = flyable(Man)
22
23 man = Man()
24 man.fly()
  带参数的类型装饰器



1 print("\n带参数的类型装饰器\n")
2 def flyable(message):
3     def flyable_to_return(cls):
4         def fly(self):
5             print(message)
6         cls.fly = fly
7         
8         return cls
9     return flyable_to_return
10
11 @flyable("我要飞的更高")
12 class Man:
13     pass
14
15 man = Man()
16 man.fly()
17
18 print("\n等价方法\n")
19
20 class Man:
21     pass
22
23 Man = flyable("我要飞的更高")(Man)
24
25 man = Man()
26 man.fly()
  备注:可以使用多个装饰器,不过要保证签名的装饰器也是返回的一个方法或类型。

自己实现@staticmethod和@classmethod
  理解了属性的取值和赋值过程,开发自定义@staticmethod和@classmethod就不成问题了,let up do it!
  代码



1 class MyStaticObject:
2     def __init__(self, fun):
3         self.fun = fun;
4
5     def __get__(self, instance, owner):
6         return self.fun
7
8 def my_static_method(fun):
9     return MyStaticObject(fun)
10
11 class MyClassObject:
12     def __init__(self, fun):
13         self.fun = fun;
14
15     def __get__(self, instance, owner):
16         def class_method(*args, **kargs):
17             return self.fun(owner, *args, **kargs)
18
19         return class_method
20
21 def my_class_method(fun):
22     return MyClassObject(fun)
23
24 class C(object):
25     """docstring for C"""
26
27     def test_instance_method(self):
28         print(self)
29
30     @staticmethod
31     def test_static_method(message):
32         print(message)
33
34     @my_static_method
35     def test_my_static_method(message):
36         print(message)
37
38     @classmethod
39     def test_class_method(cls):
40         print(cls)
41
42     @my_class_method
43     def test_my_class_method(cls):
44         print(cls)
45
46 print("\n实例方法测试")
47 c = C()
48 print(C.test_instance_method)
49 print(C.__dict__["test_instance_method"])
50 print(c.test_instance_method)   
51 C.test_instance_method(c)
52 c.test_instance_method()
53
54 print("\n静态方法测试")
55 print(C.test_static_method)
56 print(C.__dict__["test_static_method"])
57 print(c.test_static_method)
58 C.test_static_method("静态方法测试")
59 c.test_static_method("静态方法测试")
60
61 print("\n自定义静态方法测试")
62 print(C.test_my_static_method)
63 print(C.__dict__["test_my_static_method"])
64 print(c.test_my_static_method)
65 C.test_my_static_method("自定义静态方法测试")
66 c.test_my_static_method("自定义静态方法测试")
67
68 print("\n类方法测试")
69 print(C.test_class_method)
70 print(C.__dict__["test_class_method"])
71 print(c.test_class_method)
72 C.test_class_method()
73 c.test_class_method()
74
75 print("\n自定义类方法测试")
76 print(C.test_my_class_method)
77 print(C.__dict__["test_my_class_method"])
78 print(c.test_my_class_method)
79
80 C.test_my_class_method()
81 c.test_my_class_method()
82
83 print("\n对象上的方法不会返回绑定方法,对象描述符也不会起作用")
84 def test(self):
85     print(self)
86
87 c.test = test
88
89 c.test("测试")
  结果



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 测试
备注
  Python的学习和总结就到一段落了,继续弄PHP,不过还会写一篇如何用Python开发Sublime插件的教程,开发一个方便PHP开发的插件。
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-58995-1-1.html 上篇帖子: 【Python】安装NLTK 下篇帖子: Python识别验证码的开源工具
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表