Python 除了拥有实例方法外,还拥有静态方法和类方法,跟Java相比需要理解这个类方法的含义。
- class Foo(object):
- def test(self)://定义了实例方法
- print("object")
- @classmethod
- def test2(clss)://定义了类方法
- print("class")
- @staticmethod
- def test3()://定义了静态方法
- print("static")
- ff.test();//通过实例调用
- Foo.test(ff)//直接通过类的方式调用,但是需要自己传递实例引用
如果Foo有了子类并且子类覆盖了这个类方法,最终调用会调用子类的方法并传递的是子类的类对象。
- class Foo2(Foo):
- @classmethod
- def test2(self):
- print(self)
- print("foo2 object")
- f2=Foo2()
- print(f2.test2())
输出结果:
- <class '__main__.Foo2'>
- foo2 object
静态方法就跟普通的Java静态方式一样
- ff=Foo();<pre name="code" class="python">ff.test3();//使用实例调用
Foo.test3();//直接静态方式调用
其实通过以上可以看出:
实例方法,类方法,静态方法都可以通过实例或者类调用,只不过实例方法通过类调用时需要传递实例的引用(python 3可以传递任意对象,其他版本会报错)。
三种方法从不同层次上来对方法进行了描述:实例方法针对的是实例,类方法针对的是类,他们都可以继承和重新定义,而静态方法则不能继承,可以认为是全局函数。
首先,什么是函数修饰符?函数修饰符就是对原有函数做一层包装。比如有以下两个函数:
复制代码
- def func1():
- print 'I am function func1'
- def func2():
- print 'I am function func2'
|
现在我们想为这两个函数增加一段共同的操作,这时就可以使用函数修饰符。首先我们定义一个修饰函数,先不做任何处理,仅仅打印一条横线:
复制代码
- def de( f )
- def call_():
- print '-------------------------------'
- return f()
- return _call_
|
使用这个修饰符:
复制代码
- def de( f ):
- def _call_():
- print '-------------------------------'
- return f()
- return _call
- @de
- def func1():
- print 'I am function func1'
- @de
- def func2():
- print 'I am function func2'
- if name
= '__main__': func1() func2()
|
运行结果为:
复制代码
- d:\我的文档\桌面>b.py
- -------------------------------
- I am function func1
- -------------------------------
- I am function func2
- d:\我的文档\桌面>
|
可以看到,修饰符起作用了。
注意:
1.修饰符等价于包装调用:
- @de
- def func1:
- ----- 等价于 ------
- func1 = de( func1 )
|
2.修饰函数必须返回一个“可调用对象”:
- def de( f ):
- def call_():
- return f()
- return _call # 返回的是一个函数体,而非调用_call_()
|
下一个问题:如果各个被修饰函数有不同的参数,怎么处理呢?例如:
- def func1( lst1, lst2 ):
- # 合并两个list,并打印各项
- for item in lst1+lst2:
- print item
- def func2( dic ):
- # 循环dict,打印各key-value
- for k, v in dic.items():
- print k, v
|
这两个函数参数不同,又都没有异常处理,现在我们想增加上,使用修饰符这样处理:
- import sys
- import traceback
- def de( f ):
- def call_( *args, **kwargs ):
- try:
- return f( *args , **kwargs )
- except:
- print 'param type error'
- return _call
- @de
- def func1( lst1, lst2 ):
- for item in lst1+lst2:
- print item
- @de
- def func2( dic ):
- for k, v in dic.items():
- print k, v
- if name = '__main__':
- func1( [1,2], [3,4] )
- func2( [1,2] )
|
这里使用了可变参数*args和**kwargs,这样会把所有接收来的参数,原样不动的再转给原函数,是惯用法。
以上程序运行结果:
复制代码
- d:\我的文档\桌面>b.py
- 1
- 2
- 3
- 4
- param type error
- d:\我的文档\桌面>
转载请注明: 转载自canX.me
本文链接地址: 一些python
– — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – –
最近在试着读OpenStack Nova的源代码。不看别人的代码不知道自己是有多无知啊…
1.协程(Coroutine)
按我现在的理解,协程是比线程还要轻的一种程序并发执行方式。Python用“yield”这个关键字提供了对协程的支持。
看个例子就懂了:
04 | print 'foo: here ' + str (i) |
例子的输出是:
在协程里,yield起到的是类似return的作用,但是远没有return那么重:没有进程/线程调度,也就不必保存现场,函数只是暂停,过会儿还会从yield处继续执行。而如果yield后面不跟变量,甚至可以把yield看作一个标记,表示这个位置上,函数可以暂停。
上述例子中,代码的执行流程是这个样子的:第一个bar.next()输出i = 0,之后foo()函数暂停,main输出“main: here”,然后每次执行bar.next()输出“foo: here i”,然后返回打印出i。
协程的主要应用场景是服务器端的编程。因为它比线程更轻,所以可以支持更大的并发数。
举个例子,假如在服务器端生成了10000个协程,然后开始运行“调度”函数。当新的连接进入时,“调度”函数给新连接分配一个协程,而当这个协程进行IO时,会暂停让出CPU,“调度”函数再选择其它协程执行。跟进程调度很像,但是协程并没有被“阻塞”,事实上,上述的10000个协程可以是运行在一个线程中的。
OpenStack里面使用了一个叫eventlet的基于协程的网络编程库
主要参考1,2
2.@修饰符(decorator)
官方文档说修饰符只是一种语法糖(syntactic sugar),简单来说,就是下面两段代码是完全等价的。
主要参考1
3. @classmethod和@staticmethod
在一个类里面,可以存在三种方法:实例方法、类方法、静态方法,定义方法如下:
02 | def instanceFoo( self ,x): |
最显然的区别,就是他们接受的参数是不同的。实例方法必须接受一个实例(self),类方法必须接受一个类(cls),静态函数没有要求。
静态方法在python里用途不大,因为class.staticmethod()和module.normalfunction()不管从外观还是从作用都区别不大。而类方法可以用来进行类的实例化:
01 | >>> class DictSubclass( dict ): |
02 | ... def __repr__( self ): |
03 | ... return "DictSubclass" |
05 | >>> x = dict .fromkeys( 'ab' ) |
08 | >>> y = x.fromkeys( 'qwe' ) |
10 | { 'a' : None , 'b' : None } { 'q' : None , 'e' : None , 'w' : None } |
主要参考 1,2
4.*arg,**arg
这个不是指针,当参数为*arg时,表示接受一个元组;当参数为**arg时,表示接受一个字典
主要参考1
5.继承/多重继承中的参数传递
在继承/多重继承中,参数是逐级向上传递的,最后传递给object(python里一切对象的基类)时,参数应该已经处理完毕。
看个例子:
02 | def __init__( self , host, binary, topic, manager, report_interval = None , |
03 | periodic_interval = None , * args, * * kwargs): |
04 | print 'Initializing Service' |
05 | super (Service, self ).__init__( * args, * * kwargs) |
07 | print 'Service: ' + binary, args, kwargs |
10 | def __init__( self , color = 'red' , * * kwargs): |
11 | print 'Initializing Color' |
13 | super (Color, self ).__init__( * * kwargs) |
15 | print 'Color: ' , kwargs |
17 | class ColoredService(Service, Color): |
18 | def __init__( self , * args, * * kwds): |
19 | print 'Initializing Colored Service' |
20 | super (ColoredService, self ).__init__( * args, * * kwds) |
22 | c = ColoredService( 'host' , 'bin' , 'top' , 'mgr' , 'ivl' , color = 'blue' ) |
输出是:
1 | Initializing Colored Service |
5 | Service: bin () {'color': 'blue'} |
在这个例子里,ColoredService继承了Service和Color,首先初始化ColoredService,然后是Service,此时类Service“吃掉”了传来的大部分参数,只剩下{‘color’: ‘blue’}。然后初始化Color,最后是object。假如传递到object时参数还没有被吃完,python就会报“TypeError: object.__init__() takes no parameters”的错误。
而在多重继承中继承顺序的确定是用了一种叫做C3 Method Resolution Order(MRO)的算法
主要参考1,2