• python----函数进阶


    名称空间

    又名name space, 顾名思义就是存放名字的地方,存什么名字呢?举例说明,若变量x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方

    名称空间共3种,分别如下:

    1.locals: 是函数内的名称空间,包括局部变量和形参

    2.globals: 全局变量,函数定义所在模块的名字空间

    3.builtins: 内置模块的名字空间

    有名称空间才有作用域

    例子:

    def outer_function():
        b = 20
        def inner_func():
            c = 30
    
    a = 10

    在这个例子中,名称a在全局名称空间中,名称b在函数outer_function的局部名称空间,名称c则在函数inner_func的局部名称空间。
    当我们在函数inner_func时,c是个局部的名称,b是个非局部的名称,而a则是个全局的名称。在函数inner_func中,我们可以对c进行读取操作和赋值操作,而只能对b和a进行读取操作。当对b进行赋值时,一个新的名称将会被创建,这个新的名称处于inner_func函数局部名称空间中。对a进行赋值时也会在局部名称空间中创建一个新的名称。

    def outer_function():
        a = 20
    
        def inner_function():
            a = 30
            print('a = %s' % a)
    
        inner_function()
        print('a = %s' % a)
    
    
    a = 10
    outer_function()
    print('a = %s' % a)
    输出:
    a = 30
    a = 20
    a = 10

    在函数inner_function中,我们对a进行了赋值操作,但函数outer_function中的a仍然为20,全局名称空间中的a则仍然为10

    为了在函数作用域中对全局的名称进行读取或者赋值操作,需要将这个名称声明为global

    def outer_function():
        global a
        a = 20
    
        def inner_function():
            global a
            a = 30
            print('a = %s' % a)
    
        inner_function()
        print('a = %s' % a)
    
    
    a = 10
    outer_function()
    print('a = %s' % a)
    输出:
    a = 30 
    a = 30 
    a = 30

    可以看到,通过global,我们在不同的作用域对全局名称a进行了赋值操作,最后在函数inner_function中对a的赋值也就是全局名称a的值。

    作用域查找顺序:

    • locals 是函数内的名字空间,包括局部变量和形参
    • enclosing 外部嵌套函数的名字空间
    • globals 全局变量,函数定义所在模块的名字空间
    • builtins 内置模块的名字空间

    LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__

    level = 'L0'
    n = 22
    
    
    def func():
        level = 'L1'
        n = 33
        print(locals())
    
        def outer():
            n = 44
            level = 'L2'
            print(locals(),n)
    
            def inner():
                level = 'L3'
                print(locals(),n) #此外打印的n是多少?
            inner()
        outer()
    
    
    func()

    闭包:

    闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域

    闭包函数必须满足两个条件:

    1.函数内部定义的函数

    2.包含对外部作用域而非全局作用域的引用

    例1:以下仅仅在函数内部定义了一个函数,但并非闭包函数.

    def outer():
        def inner():
            print("inner func excuted")
        inner()  # 调用执行inner()函数
        print("outer func excuted")
    outer()  # 调用执行outer函数
    
    ####输出结果为##########
    inner func excuted
    outer func excuted

    例2:以下在函数内部定义了一个函数,而且还引用了一个外部变量x,那么这个是闭包函数么?答案:不是

    x = 1
    def outer():
    
        def inner():
            print("x=%s" %x)  # 引用了一个非inner函数内部的变量
            print("inner func excuted")
        inner()  # 执行inner函数
        print("outer func excuted")
    
    outer()
    #####输出结果########
    x=1
    inner func excuted
    outer func excuted

    例3:显然,下面实例满足闭包函数的条件。现在,你应该清楚,作为一个闭包函数,必须得满足上述的两个条件,缺一不可。

    def outer():
        name = 'alex'
    
        def inner():
            print("在inner里打印外层函数的变量",name)
    
        return inner
    
    
    f = outer() 
    
    f()

    装饰器:

      装饰器:外部函数传入被装饰函数名,内部函数返回装饰函数名。

      特点:1.不修改被装饰函数的调用方式 2.不修改被装饰函数的源代码

    不带参数装饰器:

    user_status = False  # 用户登录了就把这个改成True
    
    
    def login(func):
    
        def inner():
            _username = "alex"  # 假装这是DB里存的用户信息
            _password = "abc123"  # 假装这是DB里存的用户信息
            global user_status
    
            if user_status == False:
                username = input("user:")
                password = input("pasword:")
    
                if username == _username and password == _password:
                    print("welcome login....")
                    user_status = True
                else:
                    print("wrong username or password!")
            if user_status == True:
                func()
        return inner    # henan()
    
    
    def home():
        print("---首页----")
    
    
    def america():
        print("----欧美专区----")
    
    
    def japan():
        print("----日韩专区----")
    
    
    @login  # henan=login(henan)
    def henan():
        print("----河南专区----")
    
    
    henan()
    japan()

    带参数的装饰器:

    user_status = False  # 用户登录了就把这个改成True
    
    
    def login(auth_type):
        def outer(func):
    
            def inner(*args, **kwargs):
                _username = "alex"  # 假装这是DB里存的用户信息
                _password = "abc123"  # 假装这是DB里存的用户信息
                global user_status
    
                if user_status == False:
                    username = input("user:")
                    password = input("pasword:")
    
                    if username == _username and password == _password:
                        print("welcome login....")
                        user_status = True
                    else:
                        print("wrong username or password!")
                if user_status == True:
                    func(*args, **kwargs)
            return inner    # henan()
        return outer
    
    def home():
        print("---首页----")
    
    
    def america():
        print("----欧美专区----")
    
    
    # @login
    def japan():
        print("----日韩专区----")
    
    
    @login('wx')  # henan=login(henan)
    def henan(style):
        print("----河南专区----", style)
    
    # xx = login('qq')
    # print(xx)
    # henan = xx(henan)
    # print(henan)
    henan('oo')

    列表生成式:

    例子:

    现在有个需求,看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],要求你把列表里的每个值加1,你怎么实现?

    a = [i+1 for i in range(10)]
    print(a)

    这样的写法就叫做列表生成式.

    生成器:

    在Python中,这种一边循环一边计算的机制,称为生成器:generator。

    要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
    如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

    >>> L = [x * x for x in range(10)]
    >>> L
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    >>> g = (x * x for x in range(1))
    >>>next(g)
    >>>1
    >>> next(g)
    <generator object <genexpr> at 0x1022ef630

    创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator.

    所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。
    generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
    比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
    这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator

    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            print('before')
            yield b  # 把函数的执行过程冻结着这一步并且把b的值返回给外面
            print(b)
            a, b = b, a + b
            n = n + 1
        return 'Done'
    
    
    f = fib(15)  # turn function into generators
    
    for i in f:
        print(i)

    这里,最难理解的就是generator和函数的执行流程不一样。
    函数是顺序执行,遇到return语句或者最后一行函数语句就返回。
    而变成generator的函数,在每次调用next()的时候执行,
    遇到yield语句返回,再次被next()调用时从上次返回的yield语句处继续执行

    yield VS return:

    • return返回并中止function
    • yield返回数据,并冻结当前的执行过程
    • next唤醒yield并继续执行,直到下一次遇到yield
  • 相关阅读:
    点击区域外隐藏该区域,event.stopPropagation()
    PHP 笔记一(systax/variables/echo/print/Data Type)
    <hr> 的18种样式
    CSS 设置背景透明度,不影响子元素
    console.dir() 与 console.log() 区别
    JS 鼠标滚轮事件(mousewheel/DOMMouseScroll)
    HTML 字符图案
    CSS 样式优先级
    替换元素和不可替换元素,块级元素和行内元素
    CSS3 笔记五(Buttons)
  • 原文地址:https://www.cnblogs.com/cnike/p/10662275.html
Copyright © 2020-2023  润新知