一、默认参数的陷阱
- 陷阱只针对于默认参数时可变的数据类型
def func(name, list1=[]):
list1.append(name)
return list1
ret1 = func('jason')
print(ret1, id(ret1)) # ['jason'] 2246045611720
ret2 = func('carly')
print(ret2, id(ret2)) # ['jason', 'carly'] 2246045611720
由结果可知,如果默认参数是一个可变的数据类型,无论调用多少次这个默认函数,这个默认参数在内存中地址不变的。
练习1
def func(a, list1=[]):
list1.append(a)
return list1
print(func(10)) # [10]
print(func(20, [])) # [20] # 没有调用默认参数
print(func(30)) # [10, 100] # 再一次调用默认参数,而之前调用默认参数之后,list1 = [10]
练习2
def func(a, list1=[]):
list1.append(a)
return list1
ret1 = func(10)
ret2 = func(20, [])
ret3 = func(30)
print(ret1) # [10, 30]
print(ret2) # [20]
print(ret3) # [10, 30]
print(id(ret1) == id(ret3)) # True # ret1 和ret3 共用一个内存地址
二、局部作用域的坑
在函数中,如果定义了一个变量,但是在定义这个变量之前对其引用,python解释器会认为这是语法问题
比如:
count = 1
def func():
print(count)
count = 2
func()
# 程序报错
# UnboundLocalError: local variable 'count' referenced before assignment
三、global
1.可以在局部声明一个全局变量
def func():
global name
name = 'jason'
func()
print(name)
print(globals())
2.可以在局部修改一个全局变量
count = 1
def func():
global count
count += 1
func()
print(count)
四、nonlocal
1.不能操作全局变量
count = 1
def func():
nonlocal count
func()
2.局部作用域:内层函数对外层函数的局部变量进行修改
def func1():
count = 1
def func2():
nonlocal count
count += 1
func2()
print(count)
func1()
五、函数名的应用
1.函数名+()就能运行此函数
def func():
print(123)
func()
print(func, type(func))
2.函数名就是一个变量
def func():
print(123)
f = func
f() # 123
def func1():
print('this is func1')
def func2():
print('this is func2')
func2 = func1
func2() # this is func1
3.函数名可以作为容器类数据类型的元素
def func1():
print('this is func1')
def func2():
print('this is func2')
def func3():
print('this is func3')
li = [func1, func2, func3]
for i in li:
i()
4.函数名可以作为函数的参数
def func1(a):
a()
print('this is func1', end='')
def func2():
print('this is func2', end='
')
func1(func2) # this is func2 this is func1
5.函数名可以作为函数的返回值
def func1():
print('this is func1')
def func2(a):
print('this is func2')
return a
ret = func2(func1)
ret()
六、格式化输出
之前已经学习过的格式化输入%s formate
name = 'jason'
age = 24
msg1 = '我叫%s, 今年%s' % (name, age)
mgs2 = '我叫{}, 今年{}'.
新特性
name= 'jason'
age = 24
msg = f'我叫{name}, 今年{age}'
可以加表达式
dic = {'name': 'jason', 'age': 24}
msg = f"我叫{dic.get('name')}, 今年{dic['age']}"
print(msg)
count = 2
print(f'>>>{count**3}')
name = 'jason'
print(f'我的名字是{name.upper()}')
结合函数写
def _sum(a, b):
return a + b
print(f'结果为{_sum(2, 4)}')
七、迭代器
- 可迭代对象
对象:python中一切皆对象。
可迭代:更新迭代。重复的,循环的一个过程。
可迭代对象:内部含有'__iter__
'方法的对象
s = 'sdfsdf'
print(dir(s))
print('__iter__' in dir(s))
-
迭代器
可更新迭代的工具
内部含有'__iter__
'方法,并且含有'__next__
'方法的对象就是迭代器with open('test.txt', 'w', encoding='utf-8') as f1: print('__iter__' in dir(f1) and '__next__' in dir(f1)) # True
-
可迭代对象可以转化成迭代器
s = 'abc'
obj = iter(s) # 或者s.__iter__()
print(obj)
print(next(obj)) # a # 或者s1.__next__()
print(next(obj)) # b
print(next(obj)) # c
-
迭代器的优缺点
1.节省内存
2.惰性机制,next一次,只取一个值
3.速度慢
4.迭代器永远记住上此取值的位置
-
可迭代对象和迭代器的对比
-
可迭代对象是一个操作方法比较多,比较直观,存储数据相对少(几百万个对象)的一个数据集。
-
当侧重与对数据的灵活处理,并且内存空间足够,可将数据集设置为可迭代对象
-
迭代器是一个非常节省内存,可以记录取值位置,可以直接通过循环+next方法取值,但是不直观,操作方法比较单一的数据集
-
当数据量过大,内存不够处理这么多数据量,或者以节省内存为首选因素时,应将数据集设置为迭代器
-
-
while 循环模拟for 循环机制
li = [1, 2, 3, 4, 5, 6, 7, 8, 9]
obj = iter(li)
while 1:
try:
print(next(obj))
except StopIteration:
break