zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    java编译错误No enclosing instance of type TestFrame is accessible. Must qualify the allocation with an enclosing instance of type TestFrame (e.g. x.new A(
    java 2中创建线程方法
    动态规划基本思想
    关于eclipse编译一个工程多个main函数
    java Gui初识
    Eclipse中java项目的打包
    java 播放声音
    把资源文件夹导入到eclipse中
    Java建立JProgressBar
    How to grant permissions to a custom assembly that is referenced in a report in Reporting Services
  • 原文地址:https://www.cnblogs.com/cnike/p/10662275.html
Copyright © 2011-2022 走看看