Python基础学习(11)函数的陷阱 函数名的运用 f-string 迭代器
一、今日内容大纲
-
函数的陷阱
-
关键字:global、nonlocal
-
函数名的运用
-
Python 3.6 新特性:f-string
-
迭代器
二、函数的陷阱
-
默认参数的陷阱
针对默认参数是可变数据类型。无论你调用多少次这个默认参数,所调用的都是同意地址下的数据。
def func(name, list=[]): list.append(name) return list ret = func('alex') print(ret, id(ret)) # ['alex'] 2636141462472 ret2 = func('太白金星') print(ret2, id(ret2)) # ['alex', '太白金星'] 2636141462472
# Exercise 1: def func(a, list=[]): list.append(a) return list print(func(10, )) # [10] print(func(20, [])) # [20] (This call passes in another list) print(func(100, )) # [10, 100]
-
局部作用域的陷阱
count = 1 def func(): print(count) # error: local variable 'count' referenced before assignment count = 3 func() count = 1 def func(): print(count) # No error, function can find global variable 'count' func()
二、关键字 global nonlocal
-
global
-
功能一:在局部作用域声明一个全局变量。
# 在局部作用域声明一个全局变量, name = 'alex' def func(): global name name = '太白金星' print(name) func() # 太白金星 print(name) # 太白金星 # tip: name = 'alex' def func(): global name name = '太白金星' print(name) print(name) # 'alex', The function has not declared a global variable func() # 太白金星
-
功能二:对已经声明的全局变量进行修改
# 对已经声明的全局变量进行修改 count = 1 def func(): global count count += 1 print(count) # 1 func() print(count) # 2
-
-
nonlocal(Python 3x)
用于局部作用域,不能操作全局变量, 支持内层函数对外层函数的局部变量进行修改。
def wrapper(): count = 1 def inner(): nonlocal count count += 1 print(count) # 1 inner() print(count) # 2 wrapper()
四、函数名的运用
-
函数名指代的是函数的内存地址
def func(): pass print(func, type(func)) # <function func at 0x000002B8B3E41F28> <class 'NoneType'>
-
函数名可以赋值给其他变量
def func(): pass f = func print(f, type(f)) # <function func at 0x000002B8B3E41F28> <class 'function'>
-
函数名可以作为容器型数据类型的元素
def func1(): print('in func1') def func2(): print('in func2') def func3(): print('in func3') l1 = [func1, func2, func3] for i in l1: i() # result: # in func1 # in func2 # in func3
-
函数名可以作为函数的参数
def func(): print('in func') def func1(x): x() func1(func) # in func
-
函数名可以作为函数的返回值
def func(): print('in func') def func1(x): print('in func1') return x ret = func1(func) # func1() ret() # func()
五、Python 3.6 新特性:f-string
-
基本用法
name = 'taibai' age = 18 msg = f'my name is {name}, {age} years old.' print(msg) # my name is taibai, 18 years old.
-
加入表达式
dic = {'name': 'alex', 'age': 73} msg = f'my name is {dic["name"]}, {dic["age"]} years old.' print(msg) # my name is alex, 73 years old.
-
结合函数
def _sum(a, b): return a + b msg = f'result is {_sum(10, 20)}' print(msg) # result is 30 # tips: # ! , : { } 不可以出现在{}里面,会出现报错
-
优点
- 结构更加简化
- 可以结合表达式、函数进行使用
- 效率提升
六、迭代器
-
可迭代对象 iterate
根据字面意思可以理解为:"可以重复取值,更新迭代的对象“。在python中,但凡内部含有“__iter__”方法的对象,都是可迭代对象。str list tuple dic set range file_handler 等都是可迭代对象。
-
查看对象内部方法 dic()
dic() 是 directory 的缩写,会返回一个列表,这个列表中含有该对象的以字符串形式表示的所有方法名称,我们可以通过寻找返回列表内部是否具有'_iter_'来判断该对象是否是可迭代对象。
s1 = 'asdf' s2 = 199 attributes_s1 = dir(s1) attributes_s2 = dir(s2) print('__iter__' in attributes_s1) # True print('__iter__' in attributes_s2) # False
-
iterate 的特点
- 存储的数据可以直接显示,比较直观
- 拥有方法比较多
- 占用内存
- 不能直接通过for循环,不能直接取值(索引,key除外),日常使用中for循环取值其实是依赖迭代器实现的
-
迭代器 iterator
在python中,内部含有'_iter_'方法并且含有'__next__'方法的对象就是迭代器,现如今学习到的内容中,只有 file_handler 是迭代器。
with open(r'file_handler.txt', encoding='utf-8', mode='w') as file_handler: print(('__iter__' and '__next__') in dir(file_handler)) # True
-
利用 iter() 将可迭代对象转化为迭代器
s1 = 'dasd' obj = iter(s1) # s1.__iter__() 是内置函数,两者都可生成迭代器 # print(obj) # <str_iterator object at 0x000001E9BA8B8828> print(next(obj)) # d 也可写作 print(obj.__next__()) print(next(obj)) # a print(next(obj)) # s print(next(obj)) # d # print(next(obj)) # 警告: StopIteration
# Exercise: l1 = [11, 22, 33, 44, 55, 66] obj = iter(l1) print(obj) # <list_iterator object at 0x00000212C17286D8> print(next(obj)) # 11 print(next(obj)) # 22 print(next(obj)) # 33 print(next(obj)) # 44 print(next(obj)) # 55 print(next(obj)) # 66
-
iterator 的特点
优点:
- 节省内存
- 惰性机制,next()一次只取一个值
缺点:
- 不能直观的查看里面的数据
- 不走回头路,只能想下取值
-
iterator 和 iterate 的对比
-
可迭代对象 iterate:可迭代对象是一个操作方法比较多,比较直观,存储数据相对少的一个数据集。
应用:当你侧重于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择。
-
迭代器 iterator:可迭代器是一个非常节省内存,可以记录取值位置,可以通过循环+next方法取值,但是不直观,操作方法比较单一的数据集(一个迭代器一定是可迭代对象)。
应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择(可参考为什么Python把文件句柄设置为迭代器)
-
-
while 模拟 for 循环
list = [1, 2, 3, 4] # for i in list: # pass iterator = iter(list) # list.__iter__() while 1: try: i = next(iterator) # iterator.__next__() except StopIteration: break