一、函数的陷阱
1.默认参数的陷阱
针对默认参数是可变数据类型。无论你调用多少次这个默认参数,所调用的都是同意地址下的数据。
针对默认参数是可变数据类型。无论你调用多少次这个默认参数,所调用的都是同意地址下的数据。
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]
2.局部作用域的陷阱
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
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
1.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() # 太白金星
功能二:对已经声明的全局变量进行修改
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
# 对已经声明的全局变量进行修改
count = 1
def func():
global count
count += 1
print(count) # 1
func()
print(count) # 2
2.nonlocal(Python 3x)
用于局部作用域,不能操作全局变量, 支持内层函数对外层函数的局部变量进行修改。
def wrapper():
count = 1
def inner():
nonlocal count
count += 1
print(count) # 1
inner()
print(count) # 2
wrapper()
三、函数名的运用
1. 函数名指代的是函数的内存地址
def func():
pass
print(func, type(func)) # <function func at 0x000002B8B3E41F28> <class 'NoneType'>
2.函数名可以赋值给其他变量
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def func():
pass
f = func
print(f, type(f)) # <function func at 0x000002B8B3E41F28> <class 'function'>
3.函数名可以作为容器型数据类型的元素
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
4. 函数名可以作为函数的参数
def func():
print('in func')
def func1(x):
x()
func1(func) # in func
5.函数名可以作为函数的返回值
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def func():
print('in func')
def func1(x):
print('in func1')
return x
ret = func1(func) # func1()
ret() # func()
四、Python 3.6 新特性:f-string
1.基本用法
name = 'taibai'
age = 18
msg = f'my name is {name}, {age} years old.'
print(msg) # my name is taibai, 18 years old.
2.加入表达式
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.
3.结合函数
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def _sum(a, b):
return a + b
msg = f'result is {_sum(10, 20)}'
print(msg) # result is 30
# tips:
# ! , : { } 不可以出现在{}里面,会出现报错
4.优点
- 结构更加简化
- 可以结合表达式、函数进行使用
- 效率提升
五、迭代器
1.可迭代对象 iterate
根据字面意思可以理解为:"可以重复取值,更新迭代的对象“。在python中,但凡内部含有__iter__
方法的对象,都是可迭代对象。str list tuple dic set range file_handler
等都是可迭代对象。
2.查看对象内部方法 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
3.iterate 的特点
- 存储的数据可以直接显示,比较直观
- 拥有方法比较多
- 占用内存
- 不能直接通过for循环,不能直接取值(索引,key除外),日常使用中for循环取值其实是依赖迭代器实现的
4.迭代器 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
6.iterator 的特点
优点:
- 节省内存
- 惰性机制,next()一次只取一个值
缺点:
- 不能直观的查看里面的数据
- 不走回头路,只能想下取值
7.iterator 和 iterate 的对比
-
可迭代对象 iterate:可迭代对象是一个操作方法比较多,比较直观,存储数据相对少的一个数据集。
应用:当你侧重于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择。
-
迭代器 iterator:可迭代器是一个非常节省内存,可以记录取值位置,可以通过循环+next方法取值,但是不直观,操作方法比较单一的数据集(一个迭代器一定是可迭代对象)。
应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择(可参考为什么Python把文件句柄设置为迭代器)
8.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