Python 迭代器&生成器

时间:2023-03-09 06:59:26
Python 迭代器&生成器

1.内置参数

    Built-in Functions    
abs() dict() help() min() setattr()
all() dir() hex() next() slice()
any() divmod() id() object() sorted()
ascii() enumerate() input() oct() staticmethod()
bin() eval() int() open() str()
bool() exec() isinstance() ord() sum()
bytrarray() filter() issubclass() pow() super()
bytes() float() iter() print() tuple()
callable() format() len() property() type()
chr() frozenset() list() range() vars()
classmethod() getattr() locals() repr() zip()
compile() globals() map() reversed() __import__()
complex() hasattr() max() round()  
delattr() hash() memoryview() set()  

内置参数详解 https://docs.python.org/3/library/functions.html?highlight=built#ascii

2.迭代器&生成器

列表生成式,是Python内置的一种极其强大的生成list的表达式。

如果要生成一个list [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9] 可以用 range(1 , 10):

1
2
#print(list(range(1,10)))
[123456789]

如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?

1
2
3
4
5
6
= []
for in range(1,10):
    l.append(i*i)
print(l)
####打印输出####
#[1, 4, 9, 16, 25, 36, 49, 64, 81]

而列表生成式则可以用一行语句代替循环生成上面的list:

1
2
>>> print([x*for in range(1,10)])
[149162536496481]

for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:

1
2
>>> print([x*for in range(1,10if %2 ==0])
[4163664]
>>>[ i*2 for i in range(10)]
[0,1,4,6,8,10,12,14,16,18]
等于
>>>a=[]
>>>for i in range(10):
. . . a.append(i*2)
>>>a
[0,1,4,6,8,10,12,14,16,18]

小程序

str1 = ""
for i in iter(input,""): # 循环接收 input输入的内容
str1 += i print(str1)

生成器

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

>>>l = [x*x for x in range(10)]
>>>l
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>>g = (x*x for x in range(10))
>>>g
<generator object <genexpr> at 0x1022ef630>

创建Lg的区别仅在于最外层的[]()L是一个list,而g是一个generator。

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
36
>>> next(g)
49
>>> next(g)
64
>>> next(g)
81
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

  

def fib(max):
n,a,b=0,0,1
while n < max:
print(b)
a,b=b,a+b
n = n+1
return 'done'

上面的函数可以输出斐波那契数列的前N个数:

>>>fib(10)
1
1
2
3
5
8
13
21
34
55
done

生成器的特点:

1)生成器只有在调用时才会生成相应的数据;

2)只记录当前位置;

3)只有一个__next__()方法;

还可通过yield实现在单线程的情况下实现并发运算的效果:

import time
def consumer(name):
print("%s 准备吃包子!" %name)
while True:
baozi = yield
print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
c = consumer("ChenRonghua")
c.__next__() def produceer(name):
c = consumer("a")
c2 = consumer("b")
c.__next__()
c2.__next__()
print("老子开始准备做包子啦!")
for i in range(10):
time.sleep(1)
print("做了1个包子,分两半!")
c.send(i)
c2.send(i)
produceer("alex")

  迭代器

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

可以使用isinstance()判断一个对象是否是Iterable对象:

>>>from collections import Iterable
>>>isinstance([],Iterable)
True
>>>isinstance({},Iterable)
True
>>>isinstance('abc',Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

  

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

Python的for循环本质上就是通过不断调用next()函数实现的,例如:

for x in [1,2,3,4,5]:
pass

实际上完全等价于:

# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
try:
# 获得下一个值:
x = next(it)
except StopIteration:
# 遇到StopIteration就退出循环
break

  

3.Json&pickle数据序列化

用于序列化的两个模块

  • json,用于字符串 和 python数据类型间进行转换
  • pickle,用于python特有的类型 和 python的数据类型间进行转换

Json模块提供了四个功能:dumps、dump、loads、load

pickle模块提供了四个功能:dumps、dump、loads、load

info = {
"name":"alex",
"age":22
}
f = open("test.txt","w")
f.write(info)
f.close()

json序列化

 f = open("test.txt","r")

 data = eval(f.read())
f.close()
print(data['age'])

json反序列化

json能处理简单的数据类型,字典,列表,字符串。

json是所有语言通用的,json的作用是不同语言之间进行数据交互。

 #json序列化
import json
info = {
"name":"alex",
"age":22
}
f = open("test.txt","w")
#print(json.dumps(info))
f.write(json.dumps(info))
f.close()
#json反序列化
import json
f = open("test.txt","r") data = json.loads(f.read())
f.close()
print(data['age'])

json序列化,反序列化

 import pickle
def sayhi(name):
print("hello,",name)
info = {
"name":"alex",
"age":22,
"func":sayhi
}
f = open("test.txt","wb") f.write(pickle.dumps(info))
f.close()

pickle序列化

import pickle
def sayhi(name):
print("hello,",name)
f = open("test.txt","rb")
data = pickle.loads(f.read()) print(data['func']("Alex"))

pickle反序列化

4.装饰器

定义:

本质上是个函数,功能是装饰其他函数—就是为其他函数添加附加功能

装饰器原则:

1)  不能修改被装饰函数的源代码;

2)  不能修改被装饰函数的调用方式;

实现装饰器知识储备:

函数即“变量”

定义一个函数相当于把函数体赋值给了函数名

1.函数调用顺序:其他高级语言类似,python不允许在函数未声明之前,对其进行引用或者调用

错误示范:

 def foo():
print('in the foo')
bar()
foo() 报错:
in the foo
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
foo()
File "<pyshell#12>", line 3, in foo
bar()
NameError: global name 'bar' is not defined def foo():
print('foo')
bar()
foo()
def bar()
print('bar')
报错:NameError: global name 'bar' is not defined

正确示范:(注意,python为解释执行,函数foo在调用前已经声明了bar和foo,所以bar和foo无顺序之分)

def foo()
print('in the foo')
bar()
def bar():
print('in the bar')
foo() def bar():
print('in the bar')
def foo():
print('in the foo')
bar()
foo()

2.高阶函数

满足下列条件之一就可成函数为高阶函数

  1.某一函数当做参数传入另一个函数中

  2.函数的返回值包含n个函数,n>0

高阶函数示范:

def bar():
print('in the bar')
def foo(func):
res=func()
return res
foo(bar)

高阶函数的牛逼之处:

def foo(func):
return func
print('function body is %s' %(foo(bar)))
print('function name is %s' %(foo(bar).func_name))
foo(bar)()
#foo(bar)() 等同于bar=foo(bar)然后bar()
bar = foo(bar)
bar()

3.内嵌函数和变量作用域

定义:在一个函数体内创建另一个函数,这种函数就叫内嵌函数

嵌套函数:

def foo():
def bar():
print('in the bar')
bar()
foo()

局部作用域和全局做用域的访问顺序

x = 0
def grandpa():
def dad():
x = 2
def son():
x=3
print(x)
son()
dad()
grandpa()

4.高阶函数+内嵌函数=》装饰器

函数参数固定

def decorartor(func):
def wrapper(n):
print('starting')
func(n)
print('stopping')
return wrapper def test(n):
print('in the test arg is %s' %n)
decorartor(test)('alex')

函数参数不固定

def decorartor(func):
def wrapper(*args,**kwargs):
print('starting')
func(*args,**kwargs)
print('stopping')
return wrapper def test(n,x=1):
print('in the test arg is %s' %n)
decorartor(test)('alex',x=2222)

1.无参装饰器

import time
def decorator(func):
def wrapper(*args,**kwargs):
start_time=time.time()
func(*args,**kwargs)
stop_time=time.time()
print("%s" %(stop_time-start_time))
return wrapper @decorator
def test(list_test):
for i in list_test:
time.sleep(0.1)
print('-'*20,i) #decorator(test)(range(10))
test(range(10))

2.有参装饰器

import time
def timer(timeout=0):
def decorator(func):
def wrapper(*args,**kwargs):
start=time.time()
func(*args,**kwargs)
stop=time.time()
print('run time is %s ' %(stop-start))
print(timeout)
return wrapper
return decorator
@timer(2)
def test(list_test):
for i in list_test:
time.sleep(0.1)
print ('-'*20,i) #timer(timeout=10)(test)(range(10))
test(range(10))

3.终极装饰器

user,passwd = 'alex','abc123'
def auth(auth_type):
print('auth func:',auth_type)
def outer_wrapper(func):
def wrapper(*args,**kwargs):
print("wrapper func args:",*args,**kwargs)
if auth_type=="local":
username = input("Username:").strip()
password = input("Password:").strip()
if user == username and passwd == password:
res = func(*args,**kwargs)
print("---after authentication")
return res
else:
exit("\033[31;1mInvalid username or password\033[0m")
elif auth_type == "ldap":
print('搞毛线ldap,不会......') return wrapper
return outer_wrapper def index():
print("welcome to index page")
@auth(auth_type="local") #home = wrapper()
def home():
print("welcome to home page")
return "from home"
@auth(auth_type="ldap")
def bbs():
print("welcome to bbs page") index()
print(home())#wrapper()
bbs()