函数在调用的时候才执行
v1 = '张三'
def func():
v1 = '李四'
def inner():
print(v1)
v1 = '王五'
inner()
func() # 王五 函数调用才执行,inner没执行时候,v1被覆盖为王五, inner函数没有v1 ,在外部函数中找
print(v1) # 张三 在全局作用域找
v1 = '老男人'
func() # 王五
print(v1) # 老男人
可变参数的坑
# 如果默认参数指向的是可变的数据类型,那么无论调用多少次这个默认参数, 只向的都是同一个
def func(a, l1=[]):
l1.append(a)
return l1
print(func(10,)) # [10]
print(func(20, [])) # [20] 重新赋值, 和之前的不是同一个
print(func(30, )) # [10, 30]
# 先执行, 在打印,结果是不同的,修改的是同一个id地址
def func(a, l2=[]):
l2.append(a)
print(id(l2))
return l2
ret1 = func(10,) # 与ret3 是id是同一个, 先执行ret1和ret3才打印
ret2 = func(20, []) # 重新赋值了
ret3 = func(100, )
print(ret1) # [10, 100]
print(ret2) # [20]
print(ret3) # [10, 100]
# 1、局部作用域和全局作用域都有相同的值,那么局部作用域的值在使用的时候,必须先赋值,否则会有歧义,会报错
# 以下会报错 : local variable 'count' referenced before assignment
# count = 1
# def func():
# print(count)
# count = 2
# func()
# # 2、局部作用域能引用全局作用域的值,但不能改变,local variable 'count' referenced before assignment
# count = 1
# def func():
# count += 2
# func()
global
# global
# 1、在局部作用域声明一个全局变量。 必须先执行函数后,才能引用否则会报错
def func():
global name
name = '太白金星'
func()
print(name) # 太白金星
# 以下会报错 name 'age' is not defined 必须先执行函数后,才能引用否则会报错
# def func2():
# global age
# name = '太白金星'
#
# print(age)
# func2()
# 2、修改一个全局变量 没有global此时会报错的
count = 1
def func():
global count
count += 1
return count
print(func()) # 2
nonlocal
-
1,不能更改全局变量
-
2,在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。
#1. 不能够操作全局变量, 以下会报错。 # no binding for nonlocal 'count' found # count = 1 # def func(): # nonlocal count # count += 1 # func() # 2. 局部作用域:内层函数对外层函数的局部变量进行修改。 def wrapper(): num = 1 def inner(): nonlocal num num += 1 print(num) # 1 函数调用的时候才会执行 inner() print(num) # 2 wrapper()
可迭代对象、迭代器
# 判断是否是可迭代对象:内部含有__iter__ 方法 # str dic set tuple range 是可迭代对象(可迭代对象占用内存) print('__iter__' in dir('hello')) # True dir是列出所有的方法 # 迭代器 # 内部含有__iter__ 和__next__方法的对象都是迭代器 # 优点:节省内存,惰性按需索取 next # 缺点:速度慢,不会重新开始 with open('函数参数顺序.py', encoding='utf-8', mode='r') as f: print('__next__' in dir(f) and '__iter__' in dir(f)) # 可迭代对象转化为迭代器 l = [1, 2] obj = iter(l) print(obj) # 注意: 返回的是<list_iterator object at 0x103f81160> print(next(obj)) # 1 print(next(obj)) # 2 继续打印下一个值, 不会从头开始 # print(next(obj)) # StopIteration 报错 l1 = [1, 2, 3, 4, 5, 6] obj = iter(l1) for i in range(2): print(next(obj)) # 1 2 for i in range(2): print(next(obj)) # 3 4 # 可迭代对象: # 是一个私有的方法比较多,操作灵活(比如列表,字典的增删改查,字符串的常用操作方法等),比较直观,但是占用内存,而且不能直接通过循环迭代取值的这么一个数据集。 # 应用:当你侧重于对于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择。 # 迭代器: # 是一个非常节省内存,可以记录取值位置,可以直接通过循环+next方法取值,但是不直观,操作方法比较单一的数据集。 # 应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择。(可参考为什么python把文件句柄设置成迭代器)。 # for 循环 内部也是先转化为迭代器, 在next() # while模拟for的内部循环机制: l = [1, 2, 3, 4] # # 1 将可迭代对象转化成迭代器 obj = iter(l) # # 2,利用while循环,next进行取值 while 1: try: print(next(obj)) except StopIteration: break