python-函数作用域闭包

1、拆包补充,首先先看一段代码:

def func(*args, **kwargs):
    print(args)
    print(kwargs)


list1 = [1, 2, 3, 4, 6, 8]
func(list1, 100)  #([1, 2, 3, 4, 6, 8], 100)  {}
func(*list1, 100) # (1, 2, 3, 4, 6, 8, 100)  {}
func(*list1, 100, a=1)  # (1, 2, 3, 4, 6, 8, 100)  {'a': 1}
dict1 = {'a': 10, 'b': 20, 'c': 30}
func(list1, 100, dict1)
# ([1, 2, 3, 4, 6, 8], 100, {'a': 10, 'b': 20, 'c': 30})
# {}
func(*list1, 100, dict1)
# (1, 2, 3, 4, 6, 8, 100, {'a': 10, 'b': 20, 'c': 30})
# {}
func(*list1, 100, **dict1)
# (1, 2, 3, 4, 6, 8, 100)
# {'a': 10, 'b': 20, 'c': 30}

**dict1 在函数调用的时候表示拆包,会将字典中内容拆成关键字参数的形式

def func(a,b,c):
    list1 = [a,b,c]
    print(list1)
dict1={'a':10,'b':20,'c':30}
func(**dict1)  # [10, 20, 30]

2、函数之间的调用

books = ['红楼梦','西游记','水浒传','三国演义']

def show_books():
    print('-----图书馆书籍如下:-------')
    for index,book in enumerate(books):
        print('{}:{}'.format(index+1,book))

def add_books(book_name):
    if book_name:
        books.append(book_name)
        # 确认是否成功
        show_books()
        print('添加成功')
    else:
        print('书籍不能为空!')

# 添加图书
add_books('斗破苍穹')

3、返回值:

  1》如果函数没有返回值则默认的返回值是None

  2》如果在函数中添加返回值,要通过return关键字

    return关键字的作用:

      1-返回return后面值

      2-结束方法(函数)

        break ---结束循环

        return----出现在函数,表示结束函数

      3-return可以单独使用,返回值是None

        python独有的

         return a,b,c    ------  (a,b,c)

  补:return后面可以是一个参数       接收的的时候x = add(1,2)

    return后面也可以是多个参数,如果是多个参数则底层会将多个参数先放在一个元组中,将元组作为整体返回。

    接收的时候也可以是多个:return 'hello','world'          x,y = ('hello','world')       x = 'hello'  y = 'world'

list1 = [5,5,6,8,9,1]
# 找到最大值
def find_max(list1):
    if isinstance(list1,list):
        max1 = list1[0]
        for i in list1:
            if i >max1:
                max1=i
        return max1
    
m = find_max(list1)
print(m)

  找到最大值,最大值所在的下标位置。

list1 = [5,5,6,8,9,1]
# 找到最大值
def func(list1):
    if isinstance(list1,list):
        max1 = list1[0]
        max_index = 0
        for index,i in enumerate(list1):
            if i >max1:
                max1=i
                max_index = index
        # 返回结果
        return max1,max_index

m = func(list1)
print(m)  # (9, 4)

4、函数的作用域:LEGB

local  局部的  函数的本地变量

locals()   在函数中使用,获取的是当前函数的局部变量们,将函数中的局部变量放到字典中

enclosing  嵌套的  两层函数

def func():
    a = 10     ------内层函数的enclosing
    def inner_func():
        print(a)
    inner_func()

global  关键字------ 在函数中对全局变量进行声明而使用的

globals()    用在函数的外层,获取全局的变量(系统的默认产生变量+自定义的变量)

nonlocal    关键字  内层函数中想修改外部函数中变量

builtins  系统内置、所有py文件执行的时候都会加载内置模块

作用域的使用:

  全局的:

  books[]

  number = 10

  在函数中使用的时候:

  因为books是可变类型,所以可以省略global的声明

  因为number是不可变类型,所以在函数中如果想修改则必须添加global的声明

----------------------------------------------------------------------------------------------------------

number = 10 ---》 全局

def func():
    number = 0  # 局部变量
    print(number)
    number += 5  ---> 此时只能在局部变量上+5

func()
print(number)  ---》 10
number = 10

def func():
    # 如果想修改全局的变量number,必须要明确声明
    global number   ----> 明确声明以下使用的number是全局的number
    print(number)  # Unresolved reference 'number'  报错 只有局部变量才有更改“权限”,但是此时number不是局部的
    number += 5


func()
print(number)   ---》 15
number = 10

def func():
    global number
    print(number)    ---》10
    number = 9  # 相当于对全局变量number=10 的修改
    number += 5

func()
print(number)---》14

对于可变类型的话:

# 全局变量
books = ['红楼梦', '西游记', '水浒传', '三国演义']
number = 10


def func():
    # books = []
    books.append('斩龙')  # ----> 因为books是可变类型,所以可以省略global的声明
    print(books)
    global number   # -----> 因为number是不可变类型,所以在函数中如果想修改则必须添加global的声明
    number += 8


func()  #['红楼梦', '西游记', '水浒传', '三国演义', '斩龙']
print(books)  # ['红楼梦', '西游记', '水浒传', '三国演义', '斩龙']
print(number)  #  18

 5、搜索变量的规则是:

  1》如果有内部函数,先找内部函数自身的变量

  2》如果内部函数自身没有变量,则找外部函数的变量

  3》如果外部函数也不存在此变量则找全局

  4》如果全局也没有此变量则找builtins

  5》如果内部builtins也没有则报错

a = 100
b = 0
def func(b):
    a=10
    def inner_func(c):
        # global b
        # b = 1
        nonlocal b
        c = a +b +c
        b = c
        print('c:',c)
        print('b:',b)
    print('a:',a)
    print('b:',b)

    inner_func(5)

# 调用外部函数
func(8)
print(a)
print(b)

6、闭包:

  1》在一个函数中定义了另一个函数

  2》内层函数使用了外层函数的变量

  3》返回值是内层函数

  闭包的缺点:作用域没有那么直观          因为变量不会被垃圾回收所以会有一定的内存占用问题

  闭包作用:1.可以使用同级的作用域  2.读取其他元素的内部变量  3.延长作用域

  总结:

  闭包优化了变量,原来需要类对象完成的工作,闭包也可以完成。

  由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存

  闭包的好处,使代码简洁,便于阅读代码。

  闭包是理解装饰器的基础。

def out_func(n):
    a = 10
    def inner_func():
        r = a + n
        print('r的值:',r)
    print(locals())
    return inner_func

result = out_func(2)
result()  #  r的值: 12

7、函数作为参数使用的问题

  参数可以是str   int    bool   float   list   tuple   set   dict

def A():
    print('hello world!')

def func2(f):  # f = A的地址
    print('---->', f)
    f()
    print('---->over')

func2(A)

def func3(f):
    print('----->start:', f)

    def inner_func():
        print('-----》inner_func')
        f()

    print('----->end')
    return inner_func

result = func3(A)
print(result)
result()

8、装饰器:

  功能:1》引入日志  2》函数执行时间统计  3》执行函数前预备处理  4》执行函数后清理功能

     5》权限校验等场景  6》缓存

  注:写代码要遵循开放封闭的原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,他规定了已经实现的功能代码不允许被修改,但可以被拓展。

    开放:对拓展开放

    封闭:已实现的功能代码块

# 1、定义函数,闭包的原则+函数作为参数   装饰器函数
def func(f):
    print('******************1')
    def wrapper():
        print('装饰前。。。。验证是否登录')
        f()
        print('装饰后。。。。')
    print('-----------------2')
    return wrapper

# 2、功能函数
@func # 1.调用func函数  2.执行函数体内容   3.加载内部函数    4.返回内部函数wrapper 5.buy_ticket接收了func的返回值,
def buy_ticket():
    print('我可以买票去看:雷火英雄')

# 3、买票
buy_ticket()

例二:

# 定义装饰器函数
def decorator(func):  # func = house
    def wrapper():
        func()  # 此时的func就是原house()
        print('刷漆')
        print('铺地板')
        print('买家具')
        print('可以住.....')

    return wrapper


@decorator
def house():
    print('空的毛坯房...')


house()
一路独行,遇见最好的自己!!!
原文地址:https://www.cnblogs.com/rungang/p/11282023.html