迭代与函数
迭代器
迭代器是用来帮助我们记录每次迭代访问到的位置,当我们对迭代器使用next()函数的时候,迭代器会向我们返回它所记录位置的下一个位置的数据。实际上,在使用next()函数的时候,调用的就是迭代器对象的_next_方法。所以,我们要想构造一个迭代器,就要实现它的_next_方法。但这还不够,python要求迭代器本身也是可迭代的,所以我们还要为迭代器实现_iter_方法,而_iter_方法要返回一个迭代器,迭代器自身正是一个迭代器,所以迭代器的_iter_方法返回自身self即可。
总结:迭代器具有能使用next(f)函数或f.next()方法依次访问数据的功能,迭代器通过iter(f)函数或者f.__iter()__方法返回本身,即:
>>> iter(f)is f
True
迭代器协议
对象需要提供__next()__方法,它要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代。
迭代器对象与可迭代对象
- 迭代器对象
实现了迭代器协议的对象。
迭代器对象也是可迭代对象,迭代器对象具有__next__()方法和__iter__()方法。
例如文件为迭代器对象
>>> f=open(r'C:\Users\Administrator\Desktop\shici.txt','w',encoding='utf8')
>>> f.write('你好\n世界\npython\n')
13
>>> f.close()
>>> f=open(r'C:\Users\Administrator\Desktop\shici.txt',encoding='utf8')
>>> iter(f) is f
True
>>> f.__next__()
'你好\n'
>>> next(f)
'世界\n'
>>> f.__next__()
'python\n'
>>> f.__next__()
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
f.__next__()
StopIteration
- 可迭代对象
如果一个对象拥有__iter__()方法,其是可迭代对象。__iter__方法返回的是当前对象的迭代器类的实例。list、tuple、dict都是Iterable(可迭代对象),但不是Iterator(迭代器对象)。
可迭代对象可以使用内建函数iter()或__iter__()方法,把该对象变成迭代器对象。举例说明如下
>>> lt=['1','2','3']
判断列表lt是否为迭代器对象
>>> iter(lt) is lt
False
使用iter()函数或者lt.__inter__()方法将列表变为迭代器对象
>>> iterator=iter(lt)
>>> iter(iterator) is iterator
True
使用next()函数或iterator.__next__()方法访问数据
>>> iterator.__next__()
'1'
>>> next(iterator)
'2'
>>> iterator.__next__()
'3'
>>> iterator.__next__()
Traceback (most recent call last): File "<pyshell#12>", line 1, in <module> iterator.__next__()
StopIteration
在使用迭代工具如for,map时,对可迭代对象自动使用了__iter__()方法,将可迭代对象变为迭代器对象。
内置可迭代对象
- range()
range(起始值,终值,步长)
for i in range(0,5,2):
print(i)
0
2
4
- zip()
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象的迭代器。
>>> ls1=[1,2,3,4]
>>> ls2=['a','b','c']
>>> m = zip(ls1,ls2)
>>> m
<zip object at 0x000001CE37490548>
>>> for i in m:
print(i)
(1, 'a')
(2, 'b')
(3, 'c')
zip(*)与zip相反用于解压元组对象
>>> a1,a2 = zip(*m)
>>> a1
(1, 2, 3)
>>> a2
('a', 'b', 'c')
- map()函数
map() 会根据提供的函数对指定序列做映射。
map(function, iterable, …)
第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的迭代器对象。
>>> list(map(lambda x: x ** 2, [1, 2, 3, 4, 5]))# 使用 lambda 匿名函数
[1, 4, 9, 16, 25]
>>>list(map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10]))
[3, 7, 11, 15, 19]
- filter()函数
filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
filter(function, iterable)
该接收两个参数,第一个为函数,第二个为可迭代对象,可迭代对象的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的生成新的迭代器对象。
>>> lt= filter(lambda x:x%2==0,range(10))
>>> lt
<filter object at 0x000001CE37478E10>
>>> lt.__next__()
0
>>> list(lt)
[2, 4, 6, 8]
- reduce()
reduce() 函数会对参数序列中元素进行累积操作。
reduce(function, iterable[, initializer])
对可迭代对象使用函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。
>>> from functools import reduce
reduce(lambda x, y: x+y, [1,2,3,4,5]) # 使用 lambda 匿名函数
15
函数
函数是一段具有特定功能的、可重用的语句组,通过函数名来表示和调用。
作用
- 增加代码复用
- 过程分解降低编程难度
- 降低代码维护难度
定义
- def 函数名(形参…):函数体
调用
- 函数名(实参)
函数的参数传递
1、可选参数的传递
可选参数一般在非可选参数后面,定义函数时,先给出非可选参数,在给出可选参数及对应的默认值。
>>> def multiply(x,y=10):
print(x*y)
>>> multiply(99)
990
>>> multiply(99,2)
198
当函数被调用时,如果没有传入可选参数的值,则用定义函数时的默认值代替。
2、参数名称传递
函数调用时,默认采用按照顺序的方式传递给函数,采用参数名称传递方式不需要保持参数传递的顺序,只需要对每个必要参数赋值即可。
>>> def multiply(x,y=10):
print(x*y)
>>> multiply(y=5,x=20)
100
变量作用域
在python中作用域规则可以简单的归纳为LEGB原则,也就是说,对于一个变量name,首先会从当前的作用域开始查找,如果它不在函数里那就从global开始,没找到就查找builtin作用域,如果它位于函数中,就先从local作用域查找,接着如果当前的函数是一个闭包,那么就查找外层闭包的作用域,也就是规则中的E,接着是global和builtin,如果都没找到name这个变量,则抛出NameError。
-
Built-in内置函数
例如len(),sorted(),print()函数 -
全局变量
全局变量指在函数之外定义的变量,在函数内部使用时需要使用保留字global声明。
i=0
def f():
global i
print(i)
i += 1
print(i)
f()
>>>0
1
函数内部不对同名变量进行赋值操作时,会自动找寻到上一级(L→E→G)同名变量。未加说明而在函数内对一个变量赋值,那么就认为你定义了一个局部变量,从而把外部的同名对象屏蔽了。如
i=0
def f():
print(i)
f()
>>>0
- enclosure闭包作用域变量
使用nonlocal关键字调用
def closure():
count = 0
def func():
# 要使用nonlocal关键字声明
nonlocal count
count += 1
print(f'I have be called {count} times')
return func
>>> f=closure()
>>> f()
I have be called 1 time
>>> f()
I have be called 2 times
- local局部变量
局部变量是指在函数内部定义的变量,仅在函数内部有效,当函数退出时变量将不复存在。
>>> def fun(x):
i=x**2
return i
>>> fun(2)
4
>>> i
Traceback (most recent call last):
File "<pyshell#14>", line 1, in <module>
i
NameError: name 'i' is not defined
参数
- 不可变类型,传递副本给函数,函数内操作不影响原始值
def change_number(x):
x+=10
a=5
print(a)
change_number(a)
print(a)
>>>
5
5
- 可变类型,传递地址给函数,函数内操作可能影响原始值
def change_list(l):
l[0]=10
l=['wo','shi','shei']
print(l)
change_list(l)
print(l)
>>>
['wo', 'shi', 'shei']
[10, 'shi', 'shei']
常用推导式写法
ls = [1,2,3]
a=[i for i in ls if i>1] #只有if条件在for后面
print(a)
b =[i if i>1 else 0 for i in ls] #if,else存在的时候都在for前面
print(b)
[2, 3]
[0, 2, 3]