Luckylau's Blog

你懂python吗(3)

@staticmethod和@classmethod的区别

什么是python的修饰符Decorators?

​ 装饰器模式可以在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责,也能够处理那些可以撤销的职责。经常用于日志记录、性能测试等场合。

​ 想象一下这个很常见的场景,你写了一个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def A(n):
if n > 2:
print n
print "aaaaaa"
else:
print A.__name__
def B(n):
if n >2:
print n
print "bbbbbb"
else:
print B.__name__
if __name__ == '__main__':
A(3)
B(3)
#ouptput
3
aaaaaa
3
bbbbbb

用修饰符优美的表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def decorator(fn):
def inner(n):
if n>2:
print n
else:
print fn.__name__
return inner
@decorator
def A(n):
print "aaaaaa"
@decorator
def B(n):
print "bbbbbb"
if __name__ == '__main__':
A(3)
B(3)
# output
3
aaaaaa
3
bbbbbb

当有多个修饰符时候,由远及近影响,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def tag_wrap(tag):
def decorator(fn):
def inner(s):
return '<%s>%s<%s>' % (tag, fn(s), tag)
return inner
return decorator
@tag_wrap('a')
@tag_wrap('b')
@tag_wrap('c')
def greet(name):
return 'Hello, %s!' % name
if __name__ == '__main__':
print(greet('world'))
#output
<a><b><c>Hello, world!<c><b><a>

我们再举一个日志的例子

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
def log_calls(fn):
def inner(*args, **kwargs):
out = apply(fn, args, kwargs)
with open('logfile.log', 'a') as logfile:
logfile.write('%s called with args %s and kwargs %s, returning %s\n' %
(fn.__name__, args, kwargs, out))
return out
return inner
@log_calls
def fizz_buzz_or_number(i):
if i % 15 == 0:
return 'fizzbuzz'
elif i % 3 == 0:
return 'fizz'
elif i % 5 == 0:
return 'buzz'
else:
return i
if __name__ == '__main__':
for i in range(1, 31):
print(fizz_buzz_or_number(i))
#output
fizz_buzz_or_number called with args (1,) and kwargs {}, returning 1
fizz_buzz_or_number called with args (2,) and kwargs {}, returning 2
fizz_buzz_or_number called with args (3,) and kwargs {}, returning fizz
fizz_buzz_or_number called with args (4,) and kwargs {}, returning 4
fizz_buzz_or_number called with args (5,) and kwargs {}, returning buzz
fizz_buzz_or_number called with args (6,) and kwargs {}, returning fizz
fizz_buzz_or_number called with args (7,) and kwargs {}, returning 7
.
.
.

@staticmethod和@classmethod

Python其实有3个方法,即静态方法(staticmethod),类方法(classmethod)和实例方法

@staticmethod和@classmethod本身也是装饰器的一种特例。先看下面的例子:

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
def foo(x):
print "executing foo(%s)"%(x)
class A(object):
def foo(self,x):
print "executing foo(%s,%s)"%(self,x)
@classmethod
def class_foo(cls,x): #不需要self参数,但第一个参数需要是表示自身类的cls参数
print "executing class_foo(%s,%s)"%(cls,x)
@staticmethod
def static_foo(x): #不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样
print "executing static_foo(%s)"%x
if __name__ == '__main__':
a=A()
a.class_foo(3)
a.foo(3)
a.static_foo(3)
A.class_foo(3)
A.static_foo(3)
A.foo(3)
#output
executing class_foo(<class '__main__.A'>,3)
executing foo(<__main__.A object at 0x7f79857c9350>,3)
executing static_foo(3)
executing class_foo(<class '__main__.A'>,3)
executing static_foo(3)
A.foo(3)
TypeError: unbound method foo() must be called with A instance as first argument (got int instance instead)
\ 实例方法 类方法 静态方法
a = A() a.foo(x) a.class_foo(x) a.static_foo(x)
A 不可用 A.class_foo(x) A.static_foo(x

参考:

http://pythoncentral.io/difference-between-staticmethod-and-classmethod-in-python/

Luckylau wechat
如果对您有价值,看官可以打赏的!