迭代器,生成器,装饰器
常见装饰器集锦
常见装饰器的定义方式
def logincheck(func):
def wrapper(*args,**kwargs):#可变参数与可变关键字参数的适配!
print('login check!')
func(*args,**kwargs)
return wrapper
@abstractmethod, @classmethod, @staticmethod
好好利用装饰器便可以方便代码结构,让代码更清晰可观
from abc import ABC, abstractmethod#抽象基类
class DotaGame:
top_score = 0
def __init__(self, name):
self.name = name
@staticmethod
def print_game_rules():
print("游戏规则:1 xxxx游戏规则1 \n 2 xxxx游戏规则2")
@classmethod
def print_store(cls):
print("历史最高分: %s" % cls.top_score)
def print_game_name(self):
print('开始 %s 游戏' % self.name)
#usage
DotaGame('dota').print_game_name()
DotaGame.print_store()
DotaGame.print_game_rules()
>>> 开始dota游戏
>>> 历史最高分: 0
>>> 游戏规则:1 xxxx游戏规则1
>>> 2 xxxx游戏规则2
- 静态方法
类中用@staticmethod
装饰的不带self
参数的方法,类的静态方法可以直接使用类名进行调用,对于不需要访问类实例属性,类实例方法,和类属性的函数定义成静态函数 - 类方法
默认有个cls
参数,可以北类和对象进行调用,需要加上classmethod@classmethod
装饰器,对于需要访问类属性的定义成类函数 - 普通方法
默认有个self
参数,且只能被对象调用,对于需要访问实例属性、实例方法的定义成实例函数 - 抽象方法
用于程序接口的控制,含有@abstractmethod
修饰的父类无法实例化,但是继承的子类必须实现@abstractmethod
装饰的方法
ABC相关请看:(Todo list)抽象基类ABC
from abc import ABC, abstractmethod
class A(ABC):
@abstractmethod
def test(self):
print("父类abstractmethod")
pass
class B(A):
def test_1(self):
print("未覆盖父类abstractmethod")
class C(A):
def test(self):
print("覆盖父类abstractmethod")
if __name__ == '__main__':
# a = A() # 报错
# b = B() # 报错
c = C() # 正常
c.test()
>>> 覆盖父类abstractmethod
即,原有父类的函数会被覆盖(即,写了也是白写),因此很多情况下,父类的abstractmethod
的定义会用...
去填充
class Coroutine(Awaitable):
__slots__ = ()
@abstractmethod
def send(self, value):
...
@abstractmethod
def throw(self, typ, val=None, tb=None):
...
def close(self):
...
@classmethod
def __subclasshook__(cls, C):
if cls is Coroutine:
return _check_methods(C, '__await__', 'send', 'throw', 'close')
return NotImplemented
@property
@property
广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
score
在添加@property
后自动创建另一个装饰器@score.setter
,负责把一个setter方法变成属性赋值,于是我们就拥有了一个可控的属性操作。
s = Student()
s.score = 60 # OK,实际转化为s.set_score(60)
s.score # OK,实际转化为s.get_score()
60
s.score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2014 - self._birth
这里age被设置为了只读,因为age可以根据birth直接计算出来
wraps
参考文章
@wraps(view_func)的作用: 不改变使用装饰器原有函数的结构(如name, doc)
迭代器
python中很少自己定义迭代器
Iterable Iter:
- 有序的:list, tuple, string
- 无序的:set,dict
- 其他:bytes
from collections.abc import Iterable
mylist = [1,2,3,4,5]
isinstance(mylist,Iterable)#True 是否能被遍历
it = iter(mylist)
print(next(it))#每次被调用都会迭代
自定义的class需要实现__iter__
,__next__
两个函数使得该类可以被迭代
生成器
() generator,实现边迭代边输出,range(1000000000000000000000000000000)
,不可能先生成再继续
gen = (x for x in range(1,40000000000000000000000000))#生成器也是可以被迭代的!
print(isinstance(gen,Iterable))
print(next(gen))
注:如果迭代次数超过内存后会报错。
#斐波那契数列
def fibonaq(n):
res = []
a,b = 0,1
count = 0
while True:
if count >0:
break
res.append(a+b)
a,b = b, a+b
count += 1
return res
if __name__ == '__main__':
print(fibonaq(100))#会卡死!
#使用生成器去解决
def fibonaq(n):
a,b = 0, 1
count = 0
while True:
if count > n:
break
yield a + b
res.append(a+b)
a,b = b, a+b
count += 1
gen = fibonaq(1000000000000)
for i in gen:
print(i)
装饰器
在不改变原有功能代码的基础上,添加额外的功能,如用户验证等
高内聚,低耦合!!!!
decorator,Java中的装饰模式
def f1():
print('login check!')
print('this is func1')
def f2():
print('login check!')
print('this is func2')
f1()
f2()
太沙雕了,不能轻易的改变别人写的函数体,也不能轻易改变函数的使用方式
def logincheck(func):
def wrapper(*args,**kwargs):#可变参数与可变关键字参数的适配!
print('login check!')
func(*args,**kwargs)
return wrapper
def timedecorate(func):
def wrapper():
print('time decorate:',time.time())
func()
return wrapper
@logincheck
def f1(x):
print('this is func1',x)
@timedecorate
@logincheck
def f2(x,y):
print('this is func2')
def f3(x,y, **kwargs):
print('awefeaf')
print(kwargs)
f1('abc')
f2('hello','world')
f3('hello','world',a=1,b=2,c=3)