函数(二)

可变长参数

可变长参数:指的是在调用函数时,传入的参数个数可以不固定

调用函数时,传值的方式无非两种,一种是位置实参,另一种是关键字实参,因此形参也必须得有两种解决方法,以此来分别接受溢出的位置实参(*)与关键字实参(**)

牢记

一、可变长形参之*

形参中的*会将溢出的位置实参全部接收,然后存储为元组的形式,然后把元组赋值给*后的参数。需要注意的是:*后的参数名约定俗成为args。

def func(name, pwd, *args): # *后可以跟其他参数,例如abc,但尽量不要使用,应该使用args,args是约定俗成的
    print('name:', name, 'pwd:', pwd) 
    print(args) # args会接收多余的位置实参,以元组形式存储
    return 1

res = func('xiaowu', 123456, 18, 170, 140)
print(res)

# name: xiaowu pwd: 123456
# (18, 170, 140)
# 1

二、可变长形参之**

形参中的**会将溢出的关键字实参全部接收,然后存储字典的形式,然后把字典赋值给**后的参数。需要注意的是:**后的参数名约定俗成为kwargs

def func(name, pwd, **kwargs): # **后可以跟其他参数,但尽量不要使用,应该使用kwargs,kwargs是约定俗成的
    print('name:', name, 'pwd:', pwd)
    print(kwargs) # kwargs会接收多余的关键字实参,以字典形式存储
    return 1

res = func('xiaowu', 123456, age = 18, height = 170, weight = 140)
print(res)

# name: xiwowu pwd: 123456
# {'age': 18, 'height': 170, 'weight': 140}
# 1

了解

一、可变长实参之*

实参中的*,*会把*后的以元组形式存储的参数值,打散成位置实参,然后传给形参

def func(name, pwd, x, y, z): # 我们用具体的参数去接收可变长实参,会返回具体的值
    print('name:', name, 'pwd:', pwd)
    print(x, y, z)
    return 1

tup = (18, 170, 140)
res = func('xiaowu', 123456, *tup)
print(res)

# name: xiaowu pwd: 123456
# 18 170 140
# 1
def func(name, pwd, *args): 
    print('name:', name, 'pwd:', pwd)
    print(args)
    return 1

tup = (18, 170, 140)
res = func('xiaowu', 123456, *tup)
print(res)

# name: xiaowu pwd: 123456
# (18, 170, 140)
# 1

二、可变长实参之**

实参中的**,**会把**后的以字典形式存储的参数值,打散成关键字实参,然后传给形参

def func(name, pwd, **kwargs): # 我们用可变长形参去接收可变长实参,会以字典的形式返回
    print('name:', name, 'pwd:', pwd)
    print(kwargs)
    return 1

dic = {'age': 18, 'height': 170}
res = func('xiaowu', 123456, **dic)
print(res)

# name: xiaowu pwd: 123456
# {'age': 18, 'height': 170}
# 1
def func(name, pwd, age, height): # 我们用具体的参数去接收可变长实参,会返回具体的值
    print('name:', name, 'pwd:', pwd)
    print('age:', age, 'height:', htight)
    return 1

dic = {'age': 18, 'height': 170}
res = func('xiaowu', 123456, **dic)
print(res)

# name: xiaowu pwd: 123456
# age: 18 height: 170
# 1

可变长参数*和**的连用

我们可以在一个函数中同时使用*和**

def func(name, pwd, *args, **kwargs):
    print('name:', name, 'pwd:', pwd)
    print(args)
    print(kwargs)
    return 1

res = func('xiaowu', 123456, 1, 2, age=18, height=170)
print(res)

# name: xiaowu pwd: 123456
# (1, 2)
# {'age': 18, 'height': 170}
# 1

函数对象

函数是第一类对象,即函数可以被当做数据处理。

函数名等同于变量名,即变量名有的方法,函数名同样也有,被引用、当做容器元素、当做函数参数、当做函数返回值。

函数对象的四大功能

  1. 引用

    def func():
        print('from func')
    
    f = func
    print(f)
    
    # <function func at 0x000001B9B5742CA8>
    
  2. 当做参数传给一个函数

    def func():
        print('from func')
    
    def foo(m):
        m()
    
    foo(func)
    
    # from func
    
  3. 可以当做函数的返回值

    def func():
        print('from func')
    
    def foo(x):
        return x
    
    res = foo(func)
    print(res)
    res()
    
    # <function func at 0x0000018D5A072EE8>
    # from func
    
  4. 可以当做容器类型的元素

    def func():
        print('from func')
    
    function_list = [func]
    function_list[0]()
    
    # <function func at 0x0000027B7C6C2CA8>
    # from func
    

函数嵌套

函数的嵌套,就是在函数内部再定义函数。但是函数内部定义的函数,无法在函数外部使用函数内部定义的函数。

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

f2()

# NameError: name 'f2' is not defined
def f1():
    def f2():
    	print('from f2')
    f2()

f1()

# from f2

名称空间和作用域

一、名称空间

名称空间:我们之前说过创建变量,就会在内存中开辟一个空间存储变量。我们一直没有说变量名的存储,其实在内存中有一块内存存储变量名和变量之间绑定关系的空间,这个空间就叫名称空间。名称空间又分为内置名称空间、全局名称空间、局部名称空间。

1. 内置名称空间

内置名称空间:是python解释器独有的,存放着python解释器自带的名字,如int、len

内置名称空间会在python解释器启动的时候自动开辟存放python解释器自带的名字,在python解释器关闭后销毁

2. 全局名称空间

全局名称空间:除了内置名称空间和局部名称空间,其他的都存放在全局名称空间,如下面代码中的x、func、l

全局名称空间会在文件执行的时候生效,在文件执行结束后失效

x = 1

def func():
    pass

l = [1, 2]

3. 局部名称空间

局部名称空间:用于存放函数调用期间函数体产生的名字,如下面代码中的f2

局部名称空间会在文件执行时,调用函数期间的时候生效,在函数执行结束后失效

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

f1()

4. 执行顺序

三种名称空间的执行顺序是:内置 --> 全局 --> 局部

5. 查找顺序

名称空间是用来存放变量名和变量值之间的绑定关系的,所以查找变量名一定是在三个名称空间找到的。

查找顺序为:从自己的当前位置开始 --> 局部 --> 全局 --> 内置,且不可逆寻找。

二、作用域

作用域就是作用的区域,产生作用的范围。作用域分为全局作用域和局部作用域。

1. 全局作用域

全局作用域:全局有效,全部存活,包含内置名称空间和全局名称空间,全局作用域中的变量只能在全局中使用。

x = 1

def f1():
    x = 3

print(x)

# 1

2. 局部作用域

局部作用域:局部有效,临时存储,只包含局部名称空间,局部作用域中的变量只能在局部中使用。

def f1():
    def f2():
        def f3():
            print(x)
        x = 2
        f3()
    f2()

f1()

# 2

3. 注意点

作用域关系在函数定义阶段就已经固定死了,与函数的调用没有关系。

4. 补充

4.1 global关键字

global关键字可以修改全局作用域中的变量。

x = 1

def f1():
    global x
    x = 3

f1()
print(x)

# 3

4.2 nonlocal关键字

nonlocal关键字可以修改局部作用域中的变量。

def f1():
    x = 1
    def f2():
        nonlocal x
        x = 3
    f2()
    print(x)

f1()

# 3

4.3 注意

  1. 在局部想要修改全局的可变类型,不需要任何声明,可以直接修改。

  2. 在局部想要修改全局的不可变类型,需要借助global声明,声明为全局的变量,即可直接修改。

即作用域关系仅适用不可变数据类型,不适用可变数据类型

原文地址:https://www.cnblogs.com/yunluo/p/11334386.html