• 函数名-函数参数坑-迭代器


    一、关键字:global nonlocal

    默认参数的陷阱:

    # 正常
    def func(name,sex=''):
        print('name')
        print(sex)
    ​
    func('小杨')

    陷阱只针对于默认参数是可变的数据类型。如果你的默认参数指向的是可变的数据类型,那么你无论调用多少次这个默认参数,都是同一个,id也相同。

    def func(a, list=[]):
        list.append(a)
        return list
    ​
    print(func(10))             # 第一次,默认参数没有改变,里面的值传入10
    print(func(100))            # 第二次,默认参数没有改变,里面的值还是默认的时候第一次的值
    print(func(20, []))         # 第三次,默认参数从新传值了,就变成了一个新的列表从新传值
    print(func(200))            # 第四次,默认参数没有改变,里面的值还是之前第一次和第二次的值。
    # 输出
    [10]
    [10, 100]
    [20]
    [10, 100, 200]

    局部作用域的坑:在函数中,如果你定义了一个变量,但是在定义这个变量之前对其引用了,那么解释器认为:语法问题。

    你应该在使用之前先定义。

    count = 1
    def func():
        print(count)  
        count = 3
    ​
    func()
    # 报错
    UnboundLocalError: local variable 'count' referenced before assignment

    global

    在局部作用域声明一个全局变量。

    # name = '小红'    # 注释掉全局作用域下的name变量
    def func():
        global name     # 在局部声明name为全局变量
        name = '小杨'   # 不声明时,name为局部作用域的变量
        print(name)     # 会先在局部先查这个变量,没有就会去全局下查
    ​
    func()              # 要先执行函数才会声明name为全局变量
    print(name)         # 在打印name时才能找到。
    # 输出
    小杨
    小杨

    修改一个全局变量

    count = 1           # 全局定义一个count
    def func():
        global count    # 定义count为全局变量
        count += 1      # count才能自加1
    ​
    func()              # 要先执行函数,count才能自加1
    print(count)
    # 输出
    2

    nonlocal

    不能够操作全局变量。

    局部作用域:内层函数对外层函数的局部变量进行修改。

    def wrapper():          
        count = 1               # 在外层局部定义个变量
        def inner():            
            nonlocal count          # 使内层函数能够操作外层函数的局部变量
            count += 1              # 外层函数count自加1
        print(count)            # 此时打印的还是外层没有自加1的count
        inner()                 # 执行内层函数,时外层函数自加1
        print(count)            # 此时在打印的是外层函数count自加1后的值
    ​
    wrapper()
    # 输出
    1
    2

    二、函数名的运用

    函数名指向的是函数的内存地址。函数名 + ()就可以执行此函数。

    函数名就是变量。

    def func():
        print(666)
    ​
    f = func
    f1 = f
    f2 = f1
    f()
    f1()
    f2()
    # 输出
    666
    666
    666

    函数名可以作为容器类数据类型的元素。

    def func1():
        print('in func1')
    ​
    def func2():
        print('in func2')
    ​
    def func3():
        print('in func3')
    ​
    l1 = [func1, func2, func3]
    ​
    for i in l1:
        i()
        
    # 输出
    in func1
    in func2
    in func3

    函数名可以做为函数的参数。

    def func():
        print('in func')
    
    def func1(x):
        x()                    # 相当于func()
        print('in func1')
    
    func1(func)
    # 输出
    in func
    in func1

    函数名可以作为函数的返回值。

    def func():
        print('in func')
    
    def func1(x):            # 打印func1并返回x
        print('in func1')
        return x
    
    ret = func1(func)        # 打印func2并返回func,并把返回的func赋值给ret
    ret()                    # 相当于  func()
    # 输出
    in func1
    in func

    三、迭代器:

    可迭代对象

    字面意思

    对象?:python中一切皆对象。(一个实实在在存在的值)。

    可迭代?:更新迭代。重复的,类似于循环的一个过程,更新迭代每次都有新的内容,

    可以进行循环更新的一个实实在在的值。

     

    专业角度:可迭代对象?内部含有__iter__方法的对象,可迭代对象

    目前所学过的可迭代对象?:str,list,tuple,dict,set,range,文件句柄。

    获取对象的所有方法并且以字符串的形式表现出来

    dir()

    l1 = [1, 2, 3, 4, 5]
    
    print(dir(l1))
    # 输出:
    ['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

    判断一个对象是否是可迭代对象

    判断__iter__是否在dir(对象)

    l1 = [1, 2, 3, 4, 5]
    
    print('__iter__' in dir(l1))
    # 输出:
    True        # 是可迭代对象

    小结

    字面意思:可以进行循环更新的一个实实在在的值。

    专业角度:内部含有__iter__方法的对象,可迭代对象。

    判断一个对象是不是可迭代对象:判断__iter__是否在dir(对象)

    优点:

    1、存储的数据直接能显示,比较直观。

    2、拥有的方法比较多。操作方便。

    缺点:

    1、占内存。

    2、不能直接通过for循环,不能直接取值索引,key。(为什么以前可以用呢?因为,for循环在里面做了迭代器。)

     

    迭代器

    字面意思:更新迭代,器:工具,可更新迭代的工具。

    专业角度:内部含有__iter__方法并且含有__next__方法的对象就是迭代器。

     

    判断对象是否是迭代器

    可以判断是否是迭代器:__iter__and__next__在不在 dir(对象)。

    with open('文件1', encoding='utf-8', ) as f1:
        print('__iter__' in dir(f1) and '__next__' in dir(f1))
        
    # 输出:
    True

    迭代器的取值

    s1 = 'abcdefg'
    obj = iter(s1)  # 或者s1.__iter__()
    
    print(next(obj))  # print(obj.__next__)     一个就相当于取第一个的值
    print(next(obj))  # print(obj.__next__)        两个就相当于取第二个的值
    print(next(obj))  # print(obj.__next__)        三个就相当于取第三个的值
    # 输出:
    a
    b
    c

    可迭代对象如何转化成迭代器

    s1 = 'abcdefg'
    obj = iter(s1)  # 或者s1.__iter__()  把 s1 转换成迭代器 obj
    
    print('__iter__' in dir(s1) and '__next__' in dir(s1))     # s1 不是迭代器 False
    print('__iter__' in dir(obj) and '__next__' in dir(obj))   # obj 是迭代器 True
    # 输出:
    False
    True

    while循环模拟for循环机制

    1、将可迭代对象转换成迭代器。

    2、利用next对迭代器进行取值

    3、当爆错的时候,就跳出循环。

    l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99]
    
    obj = iter(l1)                # 将可迭代对象转换成迭代器。
    while 1:
        try:
            print(next(obj))    # 利用next对迭代器进行取值
        except StopIteration:
            break                # 当爆错的时候,就跳出循环。报错是因为它循环到第10次列表就没有了
    # 输出:
    11
    22
    33
    44
    55
    66
    77
    88
    99

    小结

    字面意思:更新迭代,器:工具,可更新迭代的工具。

    专业角度:内部含有__iter__方法并且含有__next__方法的对象就是迭代器。

    优点:

    1、节省内存。

    2、惰性机制。next一次,取一个值,绝不多取。

    缺点:

    1、速度慢

    2、不走回头路。

    可迭代对象与迭代器的对比

    可迭代对象是一个操作方法比较多,比较直观,存储数据相对少(几百万个对象,8G内存是可以承受的)的一个数据集。

    应用:当你侧重于对对于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择

    可迭代对象每次循环都会从头开始

    l1 = [11, 22, 33, 44, 55, 66, 77, 88]
    ​
    count = 0
    for i in l1:
        if count > 3:
            break
        else:
            print(i)
            count += 1
    print('---------------------------------')
    count = 0
    for i in l1:
        if count > 4:
            break
        else:
            print(i)
            count += 1
            
    # 输出
    11
    22
    33
    44
    ---------------------------------
    11
    22
    33
    44
    55

    是一个非常节省内存,可以记录取值位置,可以通过循环 + next 方法取值,但是不直观,操作方法比较单一的数据集。

    应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择。(可参考为什么python把文件句柄设置成迭代器)。

    迭代器每次循环会记住你上次的位置往下循环

    l1 = [11, 22, 33, 44, 55, 66, 77, 88]
    ​
    obj = iter(l1)   # 先把可迭代对象转换成迭代器
    for i in range(3):
        print(next(obj))
    ​
    print('--------------------')
        
    for i in range(4):
        print(next(obj))
    # 输出
    11
    22
    33
    --------------------
    44
    55
    66
    77
    学习之旅
  • 相关阅读:
    C# 开发Chrome内核浏览器(WebKit.net)
    SQL 存储过程语句拼接愁人的时间类型
    Linux简介
    揭秘Node.js深受欢迎的原因
    6个强大的AngularJS扩展应用
    ElasticSearch NEST
    web中的各种打印方案
    配置问题总结
    leetcode -day29 Binary Tree Inorder Traversal & Restore IP Addresses
    HBase高速导入数据--BulkLoad
  • 原文地址:https://www.cnblogs.com/XiaoYang-sir/p/14666349.html
Copyright © 2020-2023  润新知