- 一 名称空间
    - 1.1 内建名称空间
    - 1.2 全局名称空间
    - 1.3 局部名称空间
- 二 作用域
    - 2.1 全局作用域与局部作用域
    - 2.2 作用域与名字查找的优先级
**args与kwargs:**

def index(a,b,c):
    print(a,b,c)

def wrapper(*args,**kwargs):  # args=(1,2,3)    kwargs={}
    index(*args,**kwargs)  # index(*(1,2,3) ,**{})  # index(1,2,3)

wrapper(1,2,3)
**内建名称空间**
伴随python解释器的启动/关闭而产生/回收,因而是第一个被加载的名称空间,
用来存放一些内置的名字,比如内建函数名

>>> max
<built-in function max> #built-in内建

**全局名称空间**

伴随python文件的开始执行/执行完毕而产生/回收,是第二个被加载的名称空间,
文件执行过程中产生的名字都会存放于该名称空间中,如下名字

import sys #模块名sys

x=1 #变量名x

if x == 1:
    y=2 #变量名y

def foo(x): #函数名foo
    y=1
    def bar():
        pass

Class Bar: #类名Bar
    pass

**局部名称空间**

伴随函数的调用/结束而临时产生/回收,函数的形参、函数内定义的名字都会被存放于该名称空间中

def foo(x):
    y=3 #

**总结:**
    调用函数时,才会执行函数代码,名字x和y都存放于该函数的局部名称空间中
名称空间的加载顺序是:内置名称空间->全局名称空间->局部名称空间,而查找一个名字,
必须从三个名称空间之一找到,查找顺序为:局部名称空间->全局名称空间->内置名称空间。
**函数的嵌套调用**:
		在调用一个函数的过程中,又调用了其他函数

def max2(x,y):
    if x > y:
        return x
    else:
        return y

def max4(a,b,c,d):
    res1 = max2(a,b)
    res2 = max2(res1,c)
    res3 = max2(res2,d)
    print(res3)

max4(1,2,3,4)

**函数的嵌套定义**: 在函数内又定义了一个函数
def f1():  # 定义在函数内部的内容有一个效果:函数外无法访问,只有在函数内才可以访问到
    x = 111
    print(x)

f1()
# print(x)

def f1():
    def f2():
        print('from f2')
    f2()

f1()
# f2()

from math import pi

def circle(radius,mode=0):
    def perimiter(radius):
        return 2 * pi * radius

    def area(radius):
        return pi * (radius ** 2)

    if mode == 0:
        return perimiter(radius)
    elif mode == 1:
        return area(radius)

print(circle(3,0))
**函数的对象**

def foo():  # foo->函数的内存地址
    print('from foo')

1、可以被赋值
f = foo
f()   # from foo

2、可以当做参数传入
def f1(func):
    print('====>f1')
    func()

f1(foo)  # f1(函数的内存地址) # from foo

3、可以当做返回值
def f1(func):
    return func

f = f1(foo)
print(f)

4、可以当做容器类型的元素
x = 10
l = [x,foo,foo()]
# print(l)

l[1]()

def login():
    print('登录功能'.center(50, '*'))
def register():
    print("注册功能".center(50, '*'))
def transfer():
    print("转账功能".center(50, '*'))
def withdraw():
    print("提现功能".center(50, '*'))
func_dic = {
    "1": ['登录功能', login],
    "2": ['注册功能', register],
    "3": ['转账功能', transfer],
    "4": ['提现功能', withdraw],}
while True:
    print("0 退出")
    for k in func_dic:
        print(k,func_dic[k][0])
    choice = input("请输入命令编号:").strip()
    if choice == "0":
        break
    if choice in func_dic:
        func_dic[choice][1]()
    else:
        print("输入的指令错误")
**名称空间与作用域**

名称空间Namespace:存放名字与内存地址绑定关系的地方

内置名称空间:存放python解释器自带的名字
print(len)
print(input)

全局名称空间: 存放的是顶级的名字,如下x、z、f1、xxx都是
x = 100
def f1():
    y = 200

if 10 > 3:
    z = 300

    if True:
        xxx = 400

局部名称空间:存放的是函数内定义的名字
def f1():
    x = 200
f1()

**重要结论1**:局部Local-》外层函数Enclosing-》全局Global-》内置Builtin
         L->E->G->B
例1:
def f1():
    # len = 200
    print(len)

len = 100

f1()

print('=====>',len)

例2:LEGB

len = 100

def f1():
    # len = 200

    def f2():
        # len = 300
        print(len)
    len = 1111111111111111111111111111111111111111111
    f2()

f1()

**重要结论2**:名称空间的嵌套关系是在函数定义阶段、扫描语法时就确定好的,与调用位置无关

# 例1:
len = 100

def f1():
    # len = 200
    def f2():
        print(len)
    return f2

f = f1()

# print(f)

len = 6666666666666
f()

例2:
len = 100

def f1():
    def f2():
        print(len)
    # len = 200

    return f2

f = f1()

def foo():
    len = 77777
    f()

foo()

例3 :报错 例子
x = 100

def f1():
    print(x)
    x = 200

f1()

**总结:**
全局作用域:全局存活,全局有效
          内置名字空间、全局名称空间

局部作用域:临时存活,局部有效
          局部名称空间
局部是可以直接修改可变数据类型

=============》 global关键字
l = []
x = 100

def foo():
    l.append(333)

    global x
    x = 200(x=100不会改变,除非在x=200 前添加global x,
            global作用主要是修改全局不可变数据类型的)

foo()

print(l)
print(x)

=============》 nonlocal(e外层函数)关键字

x = 111
def f1():
    # x = 222
    def f2():
        # global x(改的是全局名称的x)
        nonlocal x(改的是外层函数的x)
        x = 333

    f2()
    print('==========>f1肚子里的x: ',x)
f1()
print(x)
**闭包函数:**

闭函数:定义在函数内部的函数
def outter():
    def wrapper():
        print('====>wrapper')

包函数: 内部函数引用了一个来自于外层函数的变量
def outter():
    x = 111
    def wrapper():
        print('====>wrapper',x)

为函数体传参的两种方案
方案一:直接通过参数传入即可
def wrapper(x):
    print('====>wrapper',x)

wrapper(111)
wrapper(222)

方案二:闭包函数
def outter(x):
    def wrapper():
        print('====>wrapper',x)
    return wrapper  # 不要加括号

new_wrapper1 = outter(111)
new_wrapper1()

new_wrapper2 = outter(222)
new_wrapper2()