一 迭代器
迭代:通过for循环遍历对象的每一个元素的过程;可通过collections中的Iterable类型来判断一个对象是否可迭代;
迭代器:一种可被遍历的对象,并且能作用于next()函数。从集合的第一个元素开始访问,知道所有元素访问结束。只能往后遍历不能回溯。要实现iter()和next()两个基本方法。如果类成为迭代器,需实现__iter__()和__next__()方法。不可预知序列长度。
两者区别:
-
凡是可作用于for循环的对象都是可迭代类型;
-
凡是可作用于next()函数的对象都是迭代器类型;
-
list、dict、str等是可迭代的但不是迭代器,因为next()函数无法调用它们。可以通过iter()函数将它们转换成迭代器。
-
Python的for循环本质上就是通过不断调用next()函数实现的。
- 通过内置的enumerate实现下标循环,同事迭代索引和元素本身。
for i, value in enumerate(['A', 'B', 'C']): ... print(i, value)
>>> from collections import Iterable >>> isinstance('abc',Iterable) True >>> isinstance([1,2,3],Iterable) True >>> isinstance(123,Iterable) False
二 生成器;generator;一边循环一边极速出元素的机制。
使用圆括号编写生成器推导式;
使用yield关键字。返回一个生成器generator,调用时,每次遇到yield会暂停并保存当前所有运行信息,返回yield的值。并在下一次执行next()方法时从当前位置继续运行。
>>> def fibonacci(n): ... a,b,counter = 0,1,0 ... while True: ... if counter > n: ... return ... yield a ... print(a) ... a,b = b,a+b ... counter += 1 ... >>> fib = fibonacci(10) >>> print(type(fib)) <class 'generator'> >>> for i in fib: ... print(i,end=" ") ... 0 0 1 1 1 1 2 2 3 3 5 5 8 8 13 13 21 21 34 34 55 55
>>> fib.__next__()
0
>>> fib.__next__()
0
1
>>> fib.__next__()
1
1
>>> fib.__next__()
1
2
>>> fib.__next__()
2
3
>>> fib.__next__()
3
5
>>> fib.__next__()
5
8
>>> fib.__next__()
8
13
>>> fib.__next__()
13
21
>>> fib.__next__()
21
34
>>> fib.__next__()
34
55
>>> fib.__next__()
55
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> next(fib)
0
>>> next(fib)
1
>>> next(fib)
1
>>> next(fib)
2
>>> next(fib)
3
>>> next(fib)
5
>>> next(fib)
8
>>> next(fib)
13
>>> next(fib)
21
>>> from inspect import isgeneratorfunction
>>> isgeneratorfunction(fab)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'fab' is not defined
>>> isgeneratorfunction(fib)
False
>>> isgeneratorfunction(fibonacci)
True
>>> from collections import Iterable
>>> isinstance(fib(10),Iterable)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'generator' object is not callable
>>> isinstance(fib,Iterable)
True
>>> isinstance(fibonacci,Iterable)
False
>>> isinstance(fibonacci(10),Iterable)
True
斐波那契函数: def fib(max): n,a,b = 0,1,1 while n < max: yield b a,b = b,a+b n = n+1 return 'done' >>> f = fib(6) >>> f <generator object fib at 0x0000028909469990> >>> while True: ... try: ... x = next(f) ... print('f',x) ... except StopIteration as e: ... print ('Generator return value:',e.value) ... break 杨辉三角: def triangles(): L = [1] while True: yield L k = [L[i] + L[i+1] for i in range(len(L)-1)] L = [1] + k + [1]
三 装饰器 decorator;在不修改源代码的情况下,为装饰的对象增加新的功能或者附加限制条件或者帮助输出。开放封闭原则。
函数名:outer,inner,foo
函数体:
返回值:return后的表达式
函数的内存地址:id(foo)等。
函数名加括号:对函数进行调用。如foo(),outer(foo),inner()
函数名被当做参数:outer(foo)中的foo本身是函数,但作为参数传递给了outer函数
函数名加括号被当做参数:就是先调用函数,再将返回值当做别的函数的参数,outer(foo())
返回函数名:return inner
返回函数名加括号:就是先执行函数,再将其返回值作为别的函数的返回值;return inner()
def outer(func): def inner(): print("我是内层函数!") return inner def foo(): print("我是原始函数!") outer(foo) outer(foo())
装饰器运行机制:被装饰的函数的名字会被当做参数传递给装饰函数。装饰函数执行它自己的内部代码后,会将其返回值赋值给被装饰的函数。
装饰器的返回值也是一个函数。
def outer(func): def inner(): print("认证成功!") result = func() print("日志添加成功") return result return inner @outer #@outer和@outer()有区别,无括号时,outer仍被执行 def f1(): print("业务部门1数据接口......")
f1(函数名)作为参数传递给func,也即func=f1,@outer等于outer(f1),传递的是f1的函数体(函数的整个代码结构),而非执行f1的返回值。
返回值inner;之后inner赋值给f1。也即f1函数名之后会指向inner函数。f1=inner
return inner返回的是inner整个函数名,而非inner()被调用后的返回值。
注意:f1.__name__的值变为inner
>>> test1.foo.__name__
'inner'
为防止某些依赖函数签名的代码出错,需要把f1的__name__属性赋值到inner中,使用内置的functools.wraps。
def outer(func): @functools.wraps(func) def inner(): print("认证成功!") result = func() print("日志添加成功") return result return inner
>>> test1.foo.__name__
'foo'
>>>
多个装饰器执行顺序:
def outer1(func): print ('1') def inner(*args,**kwargs): print("认证成功!") result = func(*args,**kwargs) print("日志添加成功") return result return inner def outer2(func): print ('2') def inner(*args,**kwargs): print("一条欢迎信息。。。") result = func(*args,**kwargs) print("一条欢送信息。。。") return result return inner @outer1 @outer2 def f1(name,age): print("%s 正在连接业务部门1数据接口......"%name) # 调用方法 f1("jack",18)
2
1
认证成功!
一条欢迎信息。。。
jack 正在连接业务部门1数据接口......
一条欢送信息。。。
日志添加成功
函数定义阶段:装饰器已经执行;也即未调用f1()时。
函数执行阶段:也即函数调用f1(“jack”,18),执行函数块
@outer1 @outer2 def f1(name,age): print("%s 正在连接业务部门1数据接口......"%name)
以上代码相当于outer1(outer2(f1))(),outer1和outer2返回值都是一个函数,所以outer1(outer2(f1))也是一个函数,outer1包含了outer2;f1 = outer1(outer2(f1))。
f1()相当于outer1(outer2(f1))().
执行顺序为:outer2-outer1-outer1-outer2-f1-outer2-outer1
@property装饰器.可以把类的方法伪装成属性调用的方式。也即Foo.func()的调用方法,变为Foo.func的方式。
将三个方法定义为对同一个属性的获取、修改和删除。也可以定义只读属性,即getter方法,不定义setter就是只读属性。
第一种方法:伪装属性
class People: def __init__(self,name,age): self.__name = name self.__age = age @property def age(self): #相当于get方法,result=obj.age return self.__age @age.setter def age(self,age): #相当于set方法,obj.age = 。。。 if isinstance(age,int): self.__age = age else: raise ValueError @age.deleter def age(self): print("删除年龄数据") obj = People('jack',18) print(obj.age) obj.age = 19 print('obj.age',obj.age) del obj.age
18
obj.age 19
删除年龄数据
第二种方法:builtins内置property()函数。
property()函数的参数:
- 第一个参数是方法名,调用
实例.属性时自动执行的方法 - 第二个参数是方法名,调用
实例.属性 = XXX时自动执行的方法 - 第三个参数是方法名,调用
del 实例.属性时自动执行的方法 - 第四个参数是字符串,调用
实例.属性.__doc__时的描述信息。
class People: def __init__(self,name,age): self.__name = name self.__age = age def get_age(self): return self.__age def set_age(self,age): if isinstance(age,int): self.__age = age else: raise ValueError def del_age(self): print('删除年龄数据') age = property(get_age,set_age,del_age,'年龄') obj = People('jack',18) print(obj.age) obj.age = 19 print('obj.age',obj.age) del obj.age 18 obj.age 19 删除年龄数据
浙公网安备 33010602011771号