函数的进阶(动态参数,命名空间和作用域,函数的嵌套,gloabal和nonlocal关键字)

1. 函数参数--动态传参

  昨天已经解过了传参, 如果需要给一个函数传参,而参数又是不确定的. 或者我们给一个函数传很多参数, 我的形参就要写很多, 写起来就很麻烦, 这时我们可以考虑使用动态参数.形参的第三种:动态参数.

(1) 动态参数分为两种:

  1) 动态接收位置参数

  语法: def 函数名(*args):         在形参前加个'*'符号

def chi(*food):  # *表示任意,即可以接收任意位置参数
    print('我要吃',food)  # 动态参数接收到的是tuple类型的数据
chi('大盘鸡','火锅','烤鱼','烤鸭','冰淇淋')#  我要吃 ('大盘鸡', '火锅', '烤鱼', '烤鸭', '冰淇淋')

def food(he,tang,*cai):
    print('我要吃',he,cai,tang)
food('可乐','紫菜蛋花汤','大盘鸡','烧烤')  #实参'可乐','紫菜蛋花汤'传递给了形参'he','tang',实参'大盘鸡','烧烤'传给了形参'cai'
# 我要吃 可乐 ('大盘鸡', '烧烤') 紫菜蛋花汤

# 定义求一组数相加的和的函数
def sun(*a):
    sum = 0
    for c in a:
        sum = sum + c
    return sum  #返回值为sum
print(sun(1,2,3,4,5,6,7,8,9,10))  #55

  2) 动态接收关键字参数

  语法: def    函数名(**kwargs):     在形参前面加两个'*'符号

def food(**a):   # **表示任意,即任意接收关键字参数
    print('我想吃',a)  # 接收到的是字典
print(food(主食='米饭',菜='大盘鸡',喝的='可乐'))  #我想吃 {'主食': '米饭', '菜': '大盘鸡', '喝的': '可乐'}

  形参有位置参数,默认值参数,动态位置参数(*args),动态接收关键字参数(**kwsrgs)这四种. 他们写的先后顺序是:

  位置参数>>动态接收位置参数>>默认值参数>>动态接收关键字参数

def f(*args,a,b):  #动态接收位置参数写在位置参数前会导致传入的所有实参都传递给'*args',而a,b没有值
    print(args,a,b)
f(1,2,3,4,5,6)  #会报错因为a,b没有值 TypeError: f() missing 2 required keyword-only arguments: 'a' and 'b'

def f(a,b,*args):  #改变一下位置,把*args写在位置参数后面
    print(args, a, b)
f(1,2,3,4,5,6)  #(3, 4, 5, 6) 1 2
def f(a,b,c='hello',*args):  #当默认值参数在*args前面,想要传递给*args值,就必须要传递'c'的值.不想给c值,就无法给*args值
    print(a,b,c,args)
f(1,2,3,4,5)  #1 2 3 (4, 5)
f(1,2)  #1 2 hello ()

def f(a,b,*args,c='hello'):  #把默认值参数放后面,在传递完*args的值后,最后可以用关键字参数传给c
    print(a,b,c,args)
f(1,2,3,4,c='world')  #1 2 world (3, 4)
给定义函数的两个形参*args和**kwargs, 那么这个函数可以接收所有的参数
def fuc(*args,**kwargs):
    print(args,kwargs)
fuc('hello','world','hhhh',一 ='one',二 ='two',三 ='three') 
#('hello', 'world', 'hhhh') {'一': 'one', '二': 'two', '三': 'three'}
把列表中的每一个元素作为参数, 传递给函数. 一次都传过去
def func(*args, **kwargs):  # *表示聚合,所有的位置参数, 聚合成元组 **聚合成字典
    print(args)
    print(kwargs)
lst = ["one", "two", "three", "four"]
func(*lst)  # 实参, 打散, 迭代产生的
#('one', 'two', 'three', 'four')
# {}

dic = {"name":"alex", "sex":""}
func(**dic) # 把字典打散. 以key=value形式进行传参
#()
# {'name': 'alex', 'sex': '男'}

(2) 函数的注释 先写'''''',然后在六个单引号中间位置按回车,自动生成注释

 

def f(a,b):
    '''
    介绍函数的功能,返回的值
    :param a: 介绍变量a
    :param b: 介绍变量b
    :return:  介绍返回值
    '''

    pass

 

 

 

2. 命名空间和作用域

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

def f(a):
    a = 10
    return a
print(f(3))  # 10
print(a)  #a不存在了,NameError: name 'a' is not defined

  存放名字和值的关系的空间叫命名空间. 变量在存储的时候就是存储在这片空间中的.   

  命名空间分类:        

  1. 全局命名空间--> 直接在py文件中, 函数外声明的变量都属于全局命名空间       

  2. 局部命名空间--> 在函数中声明的变量会放在局部命名空间       

  3. 内置命名空间--> 存放python解释器提供的名字, list, tuple, str, int这些都是内置命名空间

  加载顺序:       

  1. 内置命名空间

  2. 全局命名空间      

  3. 局部命名空间(函数被执⾏行行的时候)       

  取值顺序:       

  1. 局部命名空间       

  2. 全局命名空间       

  3. 内置命名空间
   

a = 10  #全局
def f():  #全局
    a = 20  #局部
    print(a)  #从局部空间取a的值
f()  #20
print(a)  #10
a = 10
def f():
    print(a)  #找不到局部a的值时,会去全局命名空间找,如果全局也没有,那么就从内置命名空间找.
f()  #10
print(a)  #10

  作用域 :  作用域就是作用范围, 按照生效范围来看分为全局作用域和局部作用域  

  全局作用域 : 包含内置命名空间和全局命名空间. 在整个文件的任何位置都可以使用(遵循 从上到下逐行执行).

  局部作用域 : 在函数内部可以使用.             

  作用域命名空间 :        

  1. 全局作用域 :    全局命名空间 + 内置命名空间       

  2. 局部作用域 :    局部命名空间    我们可以通过globals()函数来查看全局作用域中的内容,  也可以通过locals()来查看局部作用域中的变量和函数信息

 

a = 10
def func():
    a = 20
    print(a)    # 就近原则
    print(globals())  # globals() 获取到全局作用域(内置,全局)中的所有名字
    print(locals())  # locals() 查看当前作用域中的所有名字
func()
# 20
# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 
#0x0000011BD70A6160>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 
#'D:/pycharm/练习/week02/new10.py', '__cached__': None, 'a': 10, 'func': <function func at 0x0000011BD74697B8>}
# {'a': 20}

 

3. 函数的嵌套

(1)只要遇见了()就是函数的调用, 如果没有()就不是函数的调用.

(2) 函数的执行顺序

def func1():
    print("")
    def func2():
        print("")
        def func3():
            print("")
        print("")
    def func4():
        print("哈哈")
        func2()
    print("")
    func2()
func1()
#
#
#
#

 

4. gloabal, nonlocal关键字

 (1) global表示不再使用局部作用域中的内容了. 而改用全局作用域中的变量

a = 10  #全局变量
def f():
    global a  #把全局变量的a拿来用了
    a = a + 20  #改变的a是全局变量a
    print(a)
f() #30
print(a)  #30
def f():
    global a  #建立一个全局变量的a
    a = 20  #给全局变量a赋值
    print(a)
f() #20
print(a)  #20

(2)nonlocal 表示在局部作用域中, 调用其他层的局部变量(就近原则调用).

a = 10
def f():
    a = 20
    print(a)  320
    def ff():
        nonlocal a  # 找局部作用域中 离他最近的那个变量引入进来,将函数f中的a引入
        a = a + 20  #函数f中的a变成40
        print(a)  #40
    ff()
    print(a)  #40
f()
# 20
# 40
# 40
print()  # 10

 

posted @ 2018-07-13 17:37  这里有个博客  阅读(244)  评论(0编辑  收藏  举报