• python-基础


    day 12

    函数

    实参与形参

    • 实参
      分为三种:
      位置参数,关键字参数,混合参数
      混合参数的顺序: 位置参数 > 关键字参数

    • 形参
      分为三种:
      位置参数,默认值参数,动态参数(动态接收位置参数 *args 为元组,动态接收关键字参数**kwargs 为字典)
      形参顺序:位置参数 > *args > 默认值参数 > **kwargs

    def lunch(rice,*args,fruit="葡萄",vatble="白菜",**kwargs):
        print("今天午餐吃",rice,args,fruit,vatble,kwargs)
    
    lunch("东北大米","贵州苞米","崇明鲜米",fruit="芒果",vatble="鸡毛菜",meat="牛肉",big_meat="烤全羊")
    
    输出:
    今天午餐吃 东北大米 ('贵州苞米', '崇明鲜米') 芒果 鸡毛菜 {'meat': '牛肉', 'big_meat': '烤全羊'}
    

    聚合与打散

    • 形参:* 聚合成一个元组,**聚合成一个字典
    • 实参:* 打散可迭代对象(字符串,元组,列表,字典等)
    def func1(*args):  # *表示聚合,所有的位置参数, 聚合成元组
        print(args)
    
    st="abcd"
    lst = ["马虎疼", "大耳朵", "小花生", "毛尖妹妹"]
    dic = {"name":"半泽", "age":"18"}  
    tup = ("张哥哥","林妹妹")
    
    func1(*st)
    func1(*lst)  # 实参, 打散, 迭代产生的
    func1(*dic)  #字典用单个*打散只传入key值
    func1(*tup)
    func1(*range(4))
    #
    def func2(**kwargs):  # **聚合成字典
        print(kwargs)
    func2(**dic) # 把字典打散. 以key=value形式进行传参
    
    输出:
    ('a', 'b', 'c', 'd')
    ('马虎疼', '大耳朵', '小花生', '毛尖妹妹')
    ('name', 'age')
    ('张哥哥', '林妹妹')
    (0, 1, 2, 3)
    {'name': '半泽', 'age': '18'}
    

    命名空间

    在python解释器开始执⾏之后, 就会在内存中开辟⼀个空间, 每当遇到⼀个变量的时候, 就把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表⽰这个函数存在了, ⾄于函数内部的变量和逻辑, 解释器是不关⼼的. 也就是说⼀开始的时候函数只是加载进来, 仅此⽽已, 只有当函数被调⽤和访问的时候, 解释器才会根据函数内部声明的变量来进⾏开辟变量的内部空间. 随着函数执⾏完毕, 这些函数内部变量占⽤的空间也会随着函数执⾏完毕⽽被清空。

    命名空间:存放名字和值的关系的空间。

    命名空间分类:

    1. 全局命名空间--> 我们直接在py⽂件中, 函数外声明的变量都属于全局命名空间
    2. 局部命名空间--> 在函数中声明的变量会放在局部命名空间
    3. 内置命名空间--> 存放python解释器为我们提供的名字, list, tuple, str, int这些都是内置命名空间

    执行一个程序时,命名空间的加载顺序: 内置命名空间 全局命名空间 局部命名空间

    作⽤域: 作⽤域就是作⽤范围, 按照⽣效范围来看分为 全局作⽤域和局部作⽤域。
    作⽤域命名空间:

    1. 全局作⽤域: 全局命名空间 + 内置命名空间
    2. 局部作⽤域: 局部命名空间

    我们可以通过globals()函数来查看全局作⽤域中的内容, 也可以通过locals()来查看局部作⽤域中的变量和函数信息。
    locals()放在哪里,就显示哪里的命名空间变量,放在外层就显示全局命名空间。
    globals()放在哪里都是显示全局作用域的命名空间变量。

    name="name1"
    def A():
        name="name2"
        def func():
            pass
        print(locals())
    
    a=A()
    print(globals())
    
    输出:
    {'name': 'name2', 'func': <function A.<locals>.func at 0x0000021262C5C430>}
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000021260916CD0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (buoader object at 0ilt-in)>, '__file__': 'd:\Desktop\python_script\homewk.py', '__cached__': None, 'os': <module 'os' from 'D:\办公__': 'd:\Desktop
    \python\lib\os.py'>, 'I': re.IGNORECASE, 'urlopen': <function urlopen at 0x0000021260F01F70>, 'name': 'name1', 'ANORECASE, 'urlope': <function A at 0x000002126095DF70>, 'a': None}
    

    global与nonlocal

    global <变量a> 表示在局部作用域中,调用全局作用域(包括全局命名空间与内置命名空间)的a变量,还能实现在局部对全局的变量进行修改。
    nonlocal <变量a> 表示在局部作⽤域中, 调⽤⽗级命名空间中的变量,还能对父级命名空间的变量进行修改。

    global:

    name="name1"
    def A():
        name="name2"
        def func():
            global name                         # global 在内层加载全局变量name
            print("修改前内层func name:",name)
            name = "name3"                      # 在内层修改全局变量name
            print("修改后内层func name:",name)
        func()
        print("父级name:",name)
    
    a=A()
    print("全局name:",name)           # 查看全局变量已改变
    
    输出:
    修改前内层func name: name1
    修改后内层func name: name3
    父级name: name2
    全局name: name3
    

    nonlocal:

    name="name1"
    def A():
        name="name2"
        def func():
            nonlocal name                         # nonlocal 在内层加载父级局部变量name
            print("修改前内层func name:",name)
            name = "name3"                        # 在内层修改父级局部变量name
            print("修改后内层func name:",name)
        func()
        print("父级name:",name)                   #父级局部变量name已改变
    
    a=A()
    print("全局name:",name)
    
    输出:
    修改前内层func name: name2
    修改后内层func name: name3
    父级name: name3
    全局name: name1
    

    闭包

    闭包就是在内层函数中调用外层函数(非全局)的变量。

    随着函数执⾏完毕, 函数内部变量占⽤的空间也会随着函数执⾏完毕⽽被清空,而如果有闭包函数,则会让那个在内部函数中被调用的外部函数变量常驻内存。

    闭包可以让一个局部变量常驻内存,例如:

    def A():
        name="san_zhang"
        def func():
            print(name)
        print(func.__closure__)  #查看某个函数是否为闭包
        return func
    
    a1=A()   #一般在A()调用完成后,将返回值传递给a1,A()对应的空间就会删除,但当有闭包情况时,被内层调用的那个外层变量name仍会保留
    a2=a1()
    
    输出:
    (<cell at 0x000001B89BDD03A0: str object at 0x000001B89BE1DE30>,)
    san_zhang
    

    使⽤__closure__来检测函数是否是闭包. 使⽤函数名.__closure__返回cell就是闭包,返回None就不是闭包。

    迭代器

    可迭代对象(Iterable):有__iter__方法的对象都为可迭代对象。例如str, list, tuple, dict, set都能使用for循环,int没有__iter__方法,所以不是可迭代对象,使用for循环也会报错。

    dir()返回当前范围能使用的变量、方法;
    dir(a)查看对象a的属性与方法,返回为列表。
    例如:

    lst = [1,2,3]
    print(dir(lst))
    
    输出: #有__iter__
    ['__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'] 
    

    迭代器(Iterator): 有__iter__ 与 __next__两种方法的对象为迭代器。

    如何生成一个迭代器?以下it就是一个迭代器。迭代器通过__next__来逐个取值。
    it=可迭代对象.__iter__()
    it.__next__() #返回第一个值
    it.__next__() #返回第二个值

    lst = [1,2,3]   # list
    it=lst.__iter__()
    
    print(it.__next__())
    print(it.__next__())
    print(it.__next__())
    print(it.__next__())
    输出: 当使用__next__取不到值时会报错StopIteration。
    1
    2
    3
    Traceback (most recent call last):
      File "d:Desktoppython_script	est.py", line 710, in <module> 
        print(it.__next__())
    StopIteration
    

    迭代器也能使用其他方法获取值,例如for循环与list()

    lst1 = [1,2,3]
    lst2 = [4,5,6]
    it1=lst1.__iter__()
    it2=lst2.__iter__()
    
    print(list(it1))
    
    for i in it2:
        print(i)
    

    判断一个对象是可迭代对象或迭代器

    from collections import Iterable
    from collections import Iterator
    
    lst = [1,2,3]   # list
    it=lst.__iter__()
    print(isinstance(lst, Iterable))
    print(isinstance(it, Iterator))
    输出:
    True
    True
    

    使⽤while循环+迭代器来模拟for循环(必须要掌握)

    lst = [1,2,3]   # list
    
    for i in lst:
        print(i)
    
    
    ------------相当于----------------
    lst = [1,2,3]
    
    it=lst.__iter__()
    while 1:
        try:
            ret=it.__next__()
            print(ret)
        except StopIteration:
            break
    

    总结:
    Iterable: 可迭代对象. 内部包含__iter__()函数。
    Iterator: 迭代器. 内部包含__iter__() 同时包含__next__()。

    迭代器的特点:

    1. 节省内存:用一个值取一个值,而不是一次性全取完放内存中。
    2. 惰性机制:不调用__next__,不返回。
    3. 不能反复, 只能向下执⾏。

    生成器

    生成器(generator)的本质也是迭代器,我们可以通过以下三种方法获取生成器。

    1. 生成器函数
    2. 通过各种推导式来实现⽣成器
    3. 通过数据的转换也可以获取⽣成器

    生成器函数

    将函数的return换成yield,函数调用的对象就是一个生成器。与return不同的是,yield可以分段执行,return之后就不会再执行了。生成器本质是迭代器,也使用__next__逐个取值。

    def eat():
        yield("草莓")
    	yield("樱桃")
    f=eat()
    print(f.__next__())
    print(f.__next__())
    输出:
    草莓
    樱桃
    

    生成器也可使用send方法取值。与__next__的区别:

    1. send和next()都是让⽣成器向下走⼀次
    2. send("value")可以将value传到上一个yield的位置,取第一个值时不能用send(),不能给最后一个yield发送值。
    def eat():
        a=yield("草莓")
        print(a)
        b=yield("樱桃")
        print(b)
        c=yield("芒果")
    
    it=eat()
    print(dir(f))
    print(it.__next__())
    print(it.send("pear"))
    print(it.send("apple"))
    
    输出:
    草莓
    pear
    樱桃
    apple
    芒果
    

    ⽣成器可以使⽤for循环来循环获取内部的元素

    def eat():
        print(111)
        yield("草莓")
        print(222)
        yield("樱桃")
        print(333)
        yield("苹果")
    
    it=eat()
    for i in it:
        print(i,"end")
    
    输出:
    111
    草莓 end
    222
    樱桃 end
    333
    苹果 end
    

    列表推导式, ⽣成器表达式以及其他推导式

    列表推导式常用写法:
    [ 结果 for 变量 in 可迭代对象]
    [ 结果 for 变量 in 可迭代对象 if条件]
    所有的结果组成一个列表返回
    例如:

    for i in range(5):
        print(i)
    
    改为列表推导式为:
    
    lst=[i for i in range(5)]
    print(lst)
    
    输出:
    0
    1
    2
    3
    4
    [0, 1, 2, 3, 4]
    

    带条件的列表推导式:
    返回range(10)中偶数的平方

    lst=[i*i for i in range(10) if i % 2 == 0]
    print(lst)
    
    输出:
    [0, 4, 16, 36, 64]
    

    生成器表达式就是把列表推导式的[]换成(),最终的结果是一个生成器,需要逐个取值。

    #将names列表中带有两个"e"的名字删选出来
    
    names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven',
    'Joe'],
     ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    
    #常规for循环
    name_lst=[]
    for lst in names:
        for name in lst:
            if name.count("e") >= 2:
                name_lst.append(name)
    
    print(name_lst)
    
    #列表推导式
    name_lst2=[name for lst in names for name in lst if name.count("e") >= 2]
    print(name_lst2)
    
    #生成器表达式
    name_lst3=(name for lst in names for name in lst if name.count("e") >= 2)
    for i in name_lst3:  #用for取值
        print(i)
    

    列表推导式与器表达式与区别:

    1. 占用内存不同,列表推导式是将值一次性全部取出放到内存,成器表达式是一次取一个。
    2. 获取的结果不同,列表推导式的的结果是一个列表,成器表达式的结果是一个生成器。

    字典推导式
    与列表推导式类似,将[]换成{},但获取的结果要是key:value类型,最终返回一个字典。

    a=(('cat'), ('dog'),("mouse"))
    b=(('咪咪'), ('来福'),("吱吱"))
    
    dic={a[i]:b[i] for i in range(len(a))}
    print(dic)
    
    输出:
    {'cat': '咪咪', 'dog': '来福', 'mouse': '吱吱'}
    

    集合推导式
    与列表推导式类似,将[]换成{},有去重功能,但获取的结果不能是key:value类型(因为这个类型就变成了字典推导式了),最终返回一个集合。

    lst=[9,5,4,4,6,5,3]
    ret={i for i in lst}
    print(ret)
    
    输出:
    {3, 4, 5, 6, 9}
    

    总结:
    推导式有: 列表推导式, 字典推导式, 集合推导式, 没有元组推导式

    ⽣成器表达式: (结果 for 变量 in 可迭代对象 if 条件筛选)
    ⽣成器表达式可以直接获取到⽣成器对象. ⽣成器对象可以直接进⾏for循环,⽣成器具有惰性机制。

  • 相关阅读:
    怎样为flash配置Alcon调试工具
    8.9Go简介
    8.14GO之条件语句
    8.10Go之基础语法
    8.11Java之数组知识回顾
    8.13Go之常量
    8.10Go执行流、编译、特点、转义字符
    8.14Go之运算符(Operator)
    8.14Java之使用HttpClient类通过POST方式上传文件
    8.10Go之语言数据类型
  • 原文地址:https://www.cnblogs.com/huandada/p/15368685.html
Copyright © 2020-2023  润新知