16.4 Python descriptor-function and method
2016-12-06 23:52
501 查看
Python descriptor - function and method
Python descriptor - function and method准备知识
function and method
静态方法
类方法
类方法静态方法实例方法
参考文档
转载请标明出处(http://blog.csdn.net/lis_12/article/details/53495627).
properties,
methods,
static methods,
class methods, and
super()都是基于描述符实现的。本篇文章了解下就好,不必深究,如果没学过描述符的话,建议研究下描述符…
准备知识
访问属性优先级: 类属性的数据描述符 > 实例属性 > 类属性的非数据描述符,非描述符的类属性 >__getattr__();
如果一个对象定义了
__get__()方法,在属性访问时会覆盖默认行为,调用
__get__();(这个对象要为类属性)
function and method
Python面向对象的特征是建立在函数上的,非数据描述符将二者完美的结合在了一起。 类的字典将类中的方法当做函数存储。在定义类的时候,方法通常用关键字
def和
lambda来声明,这和创建函数的方式是一样的。唯一的不同之处是方法的第一个参数用来表示实例,Python约定,这个参数通常是 self, 也可以是 this 或者其它任何名字。
个人认为 方法就是一种加了命名空间的特殊函数,命名空间就是实例。
为了支持方法调用,函数定义了
__get__()方法,即当函数作为属性被访问时会调用
function.__get__()。所有的函数都是非数据描述符,它们返回绑定(bound)还是非绑定(unbound)方法取决于是被实例调用还是被类调用。
绑定方法: 函数中的第一个参数已经被设置成实例;
未绑定方法: 所有参数原封不动地传给原来的函数,包括第一个参数self;
Python模拟函数的实现
class function(object): . . . def __get__(self, obj, objtype = None): "Simulate func_descr_get() in Objects/funcobject.c" return types.methodType(self, obj, objtype)
因为function为非数据描述符,当function对象作为属性被访问时会调用
function.__get__()。
class Foo(object): def __init__(self): self.x = 1 def fun(self): print 'fun' def f1(): pass f = Foo()
方法在类字典中的存储方式为函数
print f1 #<function fun at> print type(f1) #<type 'function'> print Foo.__dict__['fun'] #<function fun at>,与f1的结果一样,虽然是类中的方法,但是按照函数存储的 print type(Foo.__dict__['fun']) == type(f1) #True,相等啊,记住方法是按照函数存储的...
此时
Foo.__dict__['fun']就是一个函数…只不过第一参数要传Foo的实例,不然可能会出现异常。
按函数的形式调用方法
print Foo.__dict__['fun'](f) #fun,将实例以参数的形式传给fun函数,等价于f.fun()
绑定方法和非绑定方法
print f.fun #bound method,此时已经将第一个参数设置成了实例f print Foo.fun #unbound method,参数原封不动 f.fun() #调用fun方法 #Foo.fun() #error,缺少实例参数,即self Foo.fun(f) #加上实例参数,等价于f.fun(),有没有感觉很和函数一样...,只不过多了个命名空间
函数为非数据描述符
print '__get__' in dir(f1) #True print '__get__' in dir(Foo.__dict__['fun']) #True
类中的函数作为属性被访问时,描述符方法
__get__()会将函数转化为方法,即当调用f.fun时,编译器会将
f.fun转化为
Foo.__dict__['fun'].__get__(f,type(f)),也就是说f.fun为
Foo.__dict__['fun'].__get__(f,type(f))的返回值。
bound = Foo.__dict__['fun'].__get__(f,type(f)) bound1 = Foo.__dict__['fun'].__get__(f) unbound = Foo.__dict__['fun'].__get__(None,Foo) print bound == f.fun #True print bound1 == f.fun #True print unbound == Foo.fun #True
由以上代码可知,
方法在类字典中的存储方式为函数;
绑定方法和非绑定方法是两个不同的类型。
绑定方法,由函数转化为绑定方法时,函数的第一个参数设置成实例,其余的参数为绑定方法的参数;
非绑定方法,由函数转化为非绑定方法时 函数中的参数原封不动的传给方法。
函数为非数据描述符,当类中的函数作为属性被访问时(即访问类中的方法),会调用
function.__get__(),
function.__get__()的返回值为方法;
函数和方法测试code
class Foo(object): def __init__(self,x = 1): self.x = x def fun(self,x): print 'fun:self.x = %s;x = %s'%(self.x,x) def fun(): pass f = Foo() f.fun(2) #fun:self.x = 1;x = 2 #传参二重奏,先将实例传进去,然后再将其他参数传进去 Foo.__dict__['fun'].__get__(f,type(f))(2) #fun:self.x = 1;x = 2,等价于f.fun(2) #验证 F = type(f).__dict__['fun'].__get__(f,type(f)) print type(F) #<type 'instancemethod'> print F == f.fun #True F(3) #fun:self.x = 1;x = 3
以下为个人理解.
传参二重奏:第一阶段先给self赋值,第二阶段给除self以外的参数赋值…
fun中的
self参数为
fun所在的命名空间,
实例f就是一个命名空间;
F = type(f).__dict__['fun'].__get__(f,type(f))先给
fun中的self赋值,相当于传参只传了一部分,即只给self赋值了(self = f),其他参数未赋值,此时F就为一个
特殊的普通函数,可以像普通函数一样调用…
继续给其他参数赋值,即给除了self之外的参数赋值,如调用函数F,
F(3),
静态方法
那些不需要self和
cls变量的方法适合为静态方法。
staticmethod()Python的模拟实现:
class staticmethod(object): "Emulate Pystaticmethod_Type() in Objects/funcobject.c" def __init__(self, f): self.f = f def __get__(self, obj, objtype=None): return self.f
因为staticmethod为非数据描述符,当staticmethod对象作为属性被访问时会调用
staticmethod.__get__()
class E(object): def f(x): print x f = staticmethod(f)
静态方法的存储方式
print E.__dict__['f'] #<staticmethod object at>
静态方法与实例方法的存储方式不一样,不是按照函数形式存储的。
从类和实例中调用静态方法
e = E() E.f(3) #3 e.f(3) #3 #E.__dict__['f'](3) #TypeError: 'staticmethod' object is not callable,不能利用这种方式调用
静态方法是非数据描述符
print '__get__' in dir(E.__dict__['f']) #True
静态方法作为属性被访问时会调用
staticmethod.__get__()
'''第一个参数为实例还是None对静态方法没影响,只要类对了就ok了''' a = E.__dict__['f'].__get__(None,E) b = E.__dict__['f'].__get__(e,E) print a == E.f #True print b == E.f #True
从以上代码可知,
静态方法在类字典中的存储方式与实例方法不同;
静态方法为非数据描述符,当静态方法作为属性被访问时会调用
staticmethod.__get__();
静态方法与实例无关,与类有关…
类方法
与静态方法不同,类方法的第一个参数用来表示类,一般为cls。classmethod()Python模拟实现:
class classmethod(object): "Emulate Pyclassmethod_Type() in Objects/funcobject.c" def __init__(self, f): self.f = f def __get__(self, obj, klass=None): if klass is None: klass = type(obj) #注意这里... def newfunc(*args): return self.f(klass, *args) return newfunc
因为classmethod为非数据描述符,当classmethod对象作为属性被访问时会调用
classmethod.__get__()。
class E(object): def f(cls,x): print x f = classmethod(f) e = E()
类方法的存储方式
print E.__dict__['f'] #<classmethod object at 0x00000000033FB168>
类方法的存储方式与静态方法,实例方法都不同。
从类和实例调用类方法
e.f(3) #3 E.f(3) #3 #E.__dict__['f']() #TypeError: 'classmethod' object is not callable,不能用这种方式调用
与实例方法的self一样,cls参数已经自动传入类方法了,无需手动传入。
类方法是非数据描述符
print '__get__' in dir(E.__dict__['f']) #True
类方法作为属性被访问时会调用
classmethod.__get__()
a = E.__dict__['f'].__get__(None,E) #<bound method type.f of <class '__main__.E'>> b = E.__dict__['f'].__get__(e,E) #<bound method type.f of <class '__main__.E'>> c = E.__dict__['f'].__get__(E,E) #<bound method type.f of <class '__main__.E'>> d = E.__dict__['f'].__get__(E) #<bound method type.f of <type 'type'>> print a == E.f #True print b == E.f #True print c == E.f #True print d == E.f #False
由上述代码可知,
类方法的存储方式与静态方法,实例方法都不同;
类方法也为非数据描述符,当类方法作为属性被访问时会调用
classmethod.__get__();
类方法与实例无关,与类有关…
类方法相比于静态方法的优势
当一个函数不需要相关的数据做参数而只需要一个类的引用的时候,这个特征就显得很有用了。类方法的一个用途是用来创建不同的类构造器。在Python 2.3中,
dict.fromkeys()可以依据一个key列表来创建一个新的字典。等价的Python实现就是:
class Dict: . . . def fromkeys(klass, iterable, value=None): "Emulate dict_fromkeys() in Objects/dictobject.c" d = klass() for key in iterable: d[key] = value return d fromkeys = classmethod(fromkeys) #现在,一个新的字典就可以这么创建: >>> Dict.fromkeys('abracadabra') {'a': None, 'r': None, 'b': None, 'c': None, 'd': None}
类方法,静态方法,实例方法
class Foo(object): def inst_f(self,a): print 'inst_fun()',a @classmethod def class_f(cls,a): print 'class fun()',a @staticmethod def static_f(a): print 'static fun()',a f = Foo()
存储方式
print type(Foo.__dict__['inst_f']) #<type 'function'> print type(Foo.__dict__['class_f']) #<type 'classmethod'> print type(Foo.__dict__['static_f']) #<type 'staticmethod'>
以函数的形式调用(从类调用方法)
Foo.inst_f(f,1) #inst_fun() 1,等价于f.inst_f() Foo.class_f(2) #class fun() 2,等价于f.class_f(2) Foo.static_f(3) #static fun() 3,等价于static_f(3)
从实例调用方法
f.inst_f(1) #inst_fun() 1,等价于f.inst_f() f.class_f(2) #class fun() 2,等价于f.class_f(2),self自动传入 f.static_f(3) #static fun() 3,等价于static_f(3),cls自动传入
从类和实例调用区别
print f.inst_f,Foo.inst_f #bound method,unbound method print f.inst_f == Foo.inst_f #False print f.class_f,Foo.class_f #bound method,bound method,两种形式是一样的 print f.class_f == Foo.class_f #True print f.static_f,Foo.static_f #function static_f,function static_f,两种是一样的 print f.static_f == Foo.static_f #True
从以上代码可知,
1) 调用实例方法时,从类和实例调用是不一样的,即实例方法与实例有关;
2) 调用类方法和静态方法时,从类和实例调用是一样的,即类方法和静态方法与实例无关。
利用
__get__()调用方法
Foo.__dict__['inst_f'].__get__(f,type(f))(1) #inst_fun() 1 Foo.__dict__['static_f'].__get__(None,type(f))(2) #static fun() 2 Foo.__dict__['class_f'].__get__(None,type(f))(3) #class fun() 3
参考文档
https://docs.python.org/2/howto/descriptor.html#definition-and-introductionhttp://blog.csdn.net/lis_12/article/details/53453665
http://pyzh.readthedocs.io/en/latest/Descriptor-HOW-TO-Guide.html
http://stackoverflow.com/questions/114214/class-method-differences-in-python-bound-unbound-and-static
相关文章推荐
- what is the different between function and method in python
- 关于python报错:TypeError: unsupported operand type(s) for +=: 'builtin_function_or_method' and 'int'
- 理解 python 的 method 和 function 兼谈 descriptor
- PL/SQL and Python scripts for the same function
- python - the first class example and method inv...
- python 编译错误TypeError: 'builtin_function_or_method' object has no attribute '__getitem__'
- Python的坑(2) -- TypeError: 'builtin_function_or_method' object is not subscriptable
- python的static class method and member
- [Python] The get() method on Python dicts and its "default" arg
- different between method and function
- round() Function in Python and Matlab
- 我所理解的Python里method和function的区别(关键词:method/方法/function/函数)
- Python - base class and the AbstractMethod/Abst...
- python decorators, classmethod and staticmethod
- Python___List Comprehension and Generator Function
- python -- fruitful function and void function
- Python里method和function的区别
- python closure and function decorators 2
- Python Function Definition and Funcion Call Discussion
- 关于Python的函数(Method)与方法(Function)