global、nonlocal、迭代器

函数在调用的时候才执行

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
    

posted on 2020-04-30 09:51  黑桃Q  阅读(121)  评论(0编辑  收藏  举报

导航