标签:修改 pat uil 函数对象 factory python 表达式 net ssm
引用:http://blog.csdn.net/slvher/article/details/42497781
这篇文章系统的介绍这几者之间的关系和区别。有兴趣的朋友可以到上面的链接查看原文,这里我把原文拷贝如下(如有侵权,通知马上删除)
====================================================================
在阅读一些开源Python库的源码时,经常会看到在某个类的成员函数前,有类似于@staticmethod或@classmethod或@property的语法糖。本质上,它们都是函数装饰器,只不过通常被用来修饰类成员函数而已。
本笔记旨在说明这些语法糖的用途,关于普通函数装饰器语法的解释,可以参考这篇笔记。
在解释这些装饰器函数前,先来分析下普通成员函数。
1. 类的普通成员函数
对于Python的类,其普通类成员函数的第一个参数默认为当前的类实例,通常的定义形式示例:
[python]
class C: def __init__(self): ## NOTICE: 不传入参数时创建实例会报错;"self"只是约定俗成的参数名而已,非语法的硬性规定
pass
我们可以通过print C.__init__查看函数__init__():[python]
>>> class C(): ... def __init__(self): ... pass ... >>> print C.__init__总之,对于类的普通成员函数来说,在创建类的具体实例前,它们是unbound method,通过类名调用时(如 C.fn()),会报错;类实例创建后,它们都是实例的bound method,只能通过实例来调用(inst = C(); inst.fn())。
2. @classmethod
根据Python文档的说明,classmethod(fn)表明函数fn是类的函数而非类实例的函数,在语法上,它要求fn的函数签名至少要有1个参数,函数被调用时,解释器会将类作为第1个参数传给fn。示例如下:
[python]
>>> class C(): ... def fn_classmethod(x): ... print x ... fn = classmethod(fn_classmethod) ... >>> C.fn可见,当调用classmethod()将fn_classmethod转换为class method后,我们可以直接通过C.fn来调用它,当然,通过C().fn()调用也可以。
[python]
>>> class C():
... @classmethod ## Python的decorator语法会保证classmethod(fn)的自动调用
... def fn(x):
... print x
...
>>> C.fn
>>> C.fn() __main__.C
classmethod的典型使用场合:
1) 直接用类来调用函数,而不用借助类实例
2) 更优雅地实现某个类的实例的构造(类似于Factory Pattern)
通常情况下,类实例是解释器自动调用类的__init__()来构造的,但借助classmethod可以在解释器调用__init__前实现一些预处理逻辑,然后将预处理后的参数传入类的构造函数来创建类实例。如dict类型支持的fromkeys()方法就是用classmethod实现的,它用dict实例当前的keys构造出一个新的dict实例。在文档Descriptor HowTo Guide最后部分给出了它对应的Python pseudo-code,感兴趣的话可以去研究一下。
关于实现类实例构造的另一个典型case,可以参考StackOverflow上的这篇问答帖。帖中Best Answer作者给出了一个典型场景,这个场景用非classmethod的方法也可以实现类实例的构造,但借助classmethod语法,可以实现的更优雅(a. 与__init__构造实例相比,classmethod方法也保证了构造逻辑代码复用度而且实现的更精简,如解析date_as_string为(year, month, day)的代码也可以被复用;b. 它不用通过类的实例调用,直接用类来调用即可构造新的实例;c. 与定义实现相同功能的全局函数相比,更符合OOP思想;d. 基类被继承时,基类中定义的classmethod也会被继承到继承类中)。
3. @staticmethod
根据Python文档的说明,staticmethod(fn)表明函数fn是类的静态方法。具体到类定义体内某个函数的定义上,如果该函数想声明称静态成员,则只需在其定义体前加上"@staticmethod"这行,利用装饰器语法糖来实现staticmethod(cls.fun)的目的。示例如下:
[python]
class C(object):
@staticmethod
def f(arg1, arg2, ...):
...
与classmethod的装饰器语法糖类似,@staticmethod会自动调用staticmethod(f)。4. @property
根据Python文档的说明,property([fget[, fset[, fdel[, doc]]]])为new-style类创建并返回property对象,该对象是根据传入的参数(fget/fset/fdel)创建的,它可以决定外部调用者对new-style类的某些属性是否具有读/写/删除权限。以官网文档给出的demo为例:
[python] view plain copy print?
上述示例中,x是类C的property对象,由于创建时传入了3个函数对象,故通过访问该属性可以实现对self._x的读/写/删除操作。具体而言,调用C().x时,解释器最终会调用getx;调用C().x = value时,解释器后最终调用setx;调用del C().x时,解释器会最终调用delx。
[python] view plain copy print?
当然,这里所说的"read-only",只是指这个属性名不会被赋值操作重新绑定新对象而已。如果这个属性名初始绑定的是个可变对象(如list或dict),则即使通过@property装饰,其绑定的对象的内容也可以通过属性名来修改。
如果想通过类的实例对象来修改或删除类实例的属性,则需用下面的代码来实现:
[python] view plain copy print?
@property除可以实现属性的只读权限功能外,还可以用在这种场景下:
类属性已经暴露给外部调用者,但由于业务需求,需要针对这个属性进行业务逻辑的修改(如增加边界判定或修改属性计算方法,等等),则此时引入property()或@property语法糖可以在修改逻辑的同时保证代码的后向兼容,外部调用者无需修改调用方式。具体的case可以参考这篇Blog中提到的场景。
【参考资料】
1. Python的几个高级语法概念浅析:lambda表达式 && 闭包 && 装饰器
2. Descriptor HowTo Guide
3. StackOverflow: Python @classmethod and @staticmethod for beginner?
4. Python Docs: classmethod
5. Python Docs: staticmethod
6. The definitive guide on how to use static, class or abstract methods in Python
7. Newfound love of @staticmethod in Python
8. Objects and classes in Python: Decorators
9. Python Docs: property()
10. Python Property
====================== EOF =====================
python 装饰器语法糖(@classmethod @staticmethod @property @name.)原理剖析和运用场景
标签:修改 pat uil 函数对象 factory python 表达式 net ssm
原文地址:http://www.cnblogs.com/killad/p/6915697.html