函数名的运用与迭代器
一、关键字:global nonlocal
默认参数的陷阱:
# 正常
def func(name,sex='男'):
print('name')
print(sex)
func('小杨')
陷阱只针对于默认参数是可变的数据类型。如果你的默认参数指向的是可变的数据类型,那么你无论调用多少次这个默认参数,都是同一个,id也相同。
def func(a, list=[]):
list.append(a)
return list
print(func(10)) # 第一次,默认参数没有改变,里面的值传入10
print(func(100)) # 第二次,默认参数没有改变,里面的值还是默认的时候第一次的值
print(func(20, [])) # 第三次,默认参数从新传值了,就变成了一个新的列表从新传值
print(func(200)) # 第四次,默认参数没有改变,里面的值还是之前第一次和第二次的值。
# 输出
[10]
[10, 100]
[20]
[10, 100, 200]
局部作用域的坑:在函数中,如果你定义了一个变量,但是在定义这个变量之前对其引用了,那么解释器认为:语法问题。
你应该在使用之前先定义。
count = 1
def func():
print(count)
count = 3
func()
# 报错
UnboundLocalError: local variable 'count' referenced before assignment
global
在局部作用域声明一个全局变量。
# name = '小红' # 注释掉全局作用域下的name变量
def func():
global name # 在局部声明name为全局变量
name = '小杨' # 不声明时,name为局部作用域的变量
print(name) # 会先在局部先查这个变量,没有就会去全局下查
func() # 要先执行函数才会声明name为全局变量
print(name) # 在打印name时才能找到。
# 输出
小杨
小杨
修改一个全局变量
count = 1 # 全局定义一个count
def func():
global count # 定义count为全局变量
count += 1 # count才能自加1
func() # 要先执行函数,count才能自加1
print(count)
# 输出
2
nonlocal
不能够操作全局变量。
局部作用域:内层函数对外层函数的局部变量进行修改。
def wrapper():
count = 1 # 在外层局部定义个变量
def inner():
nonlocal count # 使内层函数能够操作外层函数的局部变量
count += 1 # 外层函数count自加1
print(count) # 此时打印的还是外层没有自加1的count
inner() # 执行内层函数,时外层函数自加1
print(count) # 此时在打印的是外层函数count自加1后的值
wrapper()
# 输出
1
2
二、函数名的运用
函数名指向的是函数的内存地址。函数名 + ()就可以执行此函数。
函数名就是变量。
def func():
print(666)
f = func
f1 = f
f2 = f1
f()
f1()
f2()
# 输出
666
666
666
函数名可以作为容器类数据类型的元素。
def func1():
print('in func1')
def func2():
print('in func2')
def func3():
print('in func3')
l1 = [func1, func2, func3]
for i in l1:
i()
# 输出
in func1
in func2
in func3
函数名可以做为函数的参数。
def func():
print('in func')
def func1(x):
x() # 相当于func()
print('in func1')
func1(func)
# 输出
in func
in func1
函数名可以作为函数的返回值。
def func():
print('in func')
def func1(x): # 打印func1并返回x
print('in func1')
return x
ret = func1(func) # 打印func2并返回func,并把返回的func赋值给ret
ret() # 相当于 func()
# 输出
in func1
in func
三、迭代器:
可迭代对象
字面意思
对象?:python中一切皆对象。(一个实实在在存在的值)。
可迭代?:更新迭代。重复的,类似于循环的一个过程,更新迭代每次都有新的内容,
可以进行循环更新的一个实实在在的值。
专业角度:可迭代对象?内部含有__iter__
方法的对象,可迭代对象
目前所学过的可迭代对象?:str,list,tuple,dict,set,range,文件句柄。
获取对象的所有方法并且以字符串的形式表现出来
dir()
l1 = [1, 2, 3, 4, 5]
print(dir(l1))
# 输出:
['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
判断一个对象是否是可迭代对象
判断__iter__
是否在dir(对象)
l1 = [1, 2, 3, 4, 5]
print('__iter__' in dir(l1))
# 输出:
True # 是可迭代对象
小结
字面意思:可以进行循环更新的一个实实在在的值。
专业角度:内部含有__iter__
方法的对象,可迭代对象。
判断一个对象是不是可迭代对象:判断__iter__
是否在dir(对象)
优点:
1、存储的数据直接能显示,比较直观。
2、拥有的方法比较多。操作方便。
缺点:
1、占内存。
2、不能直接通过for循环,不能直接取值索引,key。(为什么以前可以用呢?因为,for循环在里面做了迭代器。)
迭代器
字面意思:更新迭代,器:工具,可更新迭代的工具。
专业角度:内部含有__iter__
方法并且含有__next__
方法的对象就是迭代器。
判断对象是否是迭代器
可以判断是否是迭代器:__iter__
and__next__
在不在 dir(对象)。
with open('文件1', encoding='utf-8', ) as f1:
print('__iter__' in dir(f1) and '__next__' in dir(f1))
# 输出:
True
迭代器的取值
s1 = 'abcdefg'
obj = iter(s1) # 或者s1.__iter__()
print(next(obj)) # print(obj.__next__) 一个就相当于取第一个的值
print(next(obj)) # print(obj.__next__) 两个就相当于取第二个的值
print(next(obj)) # print(obj.__next__) 三个就相当于取第三个的值
# 输出:
a
b
c
可迭代对象如何转化成迭代器
s1 = 'abcdefg'
obj = iter(s1) # 或者s1.__iter__() 把 s1 转换成迭代器 obj
print('__iter__' in dir(s1) and '__next__' in dir(s1)) # s1 不是迭代器 False
print('__iter__' in dir(obj) and '__next__' in dir(obj)) # obj 是迭代器 True
# 输出:
False
True
while循环模拟for循环机制
1、将可迭代对象转换成迭代器。
2、利用next对迭代器进行取值
3、当爆错的时候,就跳出循环。
l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99]
obj = iter(l1) # 将可迭代对象转换成迭代器。
while 1:
try:
print(next(obj)) # 利用next对迭代器进行取值
except StopIteration:
break # 当爆错的时候,就跳出循环。报错是因为它循环到第10次列表就没有了
# 输出:
11
22
33
44
55
66
77
88
99
小结
字面意思:更新迭代,器:工具,可更新迭代的工具。
专业角度:内部含有__iter__
方法并且含有__next__
方法的对象就是迭代器。
优点:
1、节省内存。
2、惰性机制。next一次,取一个值,绝不多取。
缺点:
1、速度慢
2、不走回头路。
可迭代对象与迭代器的对比
可迭代对象是一个操作方法比较多,比较直观,存储数据相对少(几百万个对象,8G内存是可以承受的)的一个数据集。
应用:当你侧重于对对于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择
可迭代对象每次循环都会从头开始
l1 = [11, 22, 33, 44, 55, 66, 77, 88]
count = 0
for i in l1:
if count > 3:
break
else:
print(i)
count += 1
print('---------------------------------')
count = 0
for i in l1:
if count > 4:
break
else:
print(i)
count += 1
# 输出
11
22
33
44
---------------------------------
11
22
33
44
55
迭代器是一个非常节省内存,可以记录取值位置,可以通过循环 + next 方法取值,但是不直观,操作方法比较单一的数据集。
应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择。(可参考为什么python把文件句柄设置成迭代器)。
迭代器每次循环会记住你上次的位置往下循环
l1 = [11, 22, 33, 44, 55, 66, 77, 88]
obj = iter(l1) # 先把可迭代对象转换成迭代器
for i in range(3):
print(next(obj))
print('--------------------')
for i in range(4):
print(next(obj))
# 输出
11
22
33
--------------------
44
55
66
77
本文来自博客园,作者:Mr-Yang`,转载请注明原文链接:https://www.cnblogs.com/XiaoYang-sir/p/14666349.html