python3--函数进阶

例子

def func(a,b,c,d,e,f,g):

    pass

print(func(a, b , c, d, e, f, g))

如果再加30个参数呢?,在后面继续添加?有没有万能的参数,可以代表一切参数呢?

*args 动态参数,万能参数

args接收的就是实参对应的所有位置参数,并将其放在元组中,它不会接收关键字参数

例子

def func(*args):
    pass
func(1,2,3,4,5,6,7,8,9)

执行没有报错

def func1(*args):
    print(args)
func1(1,2,3,4,5,6,7,8,9)

执行结果是一个元组

(1, 2, 3, 4, 5, 6, 7, 8, 9)

形参对应顺序

错误的示例

def func(*args,a,b,c,d,e='sex'):
    print(args)
    print(a)
    print(b)
    print(c)
    print(d)
func(1,2,3,4,5)

执行报错

TypeError: func() missing 4 required keyword-only arguments: 'a', 'b', 'c', and 'd'

因为*args接收了所有实参,所以缺少了a,b,c,d

形参对应顺序

#位置参数,*args,默认参数

正确的示例

def func(a,b,c,d,*args,e='男'):
    print(a)
    print(b)
    print(c)
    print(d)
    print(args)
    print(e)
func(1,2,3,4,10,9,8,7,e='女')

执行结果

*args参数,可以不传,默认为空()

示例

def func(a,b,c,d,*args,e='男'):
    print(a)
    print(b)
    print(c)
    print(d)
    print(args)
    print(e)
func(1,2,3,4,e='女')

执行结果

*args名字可以随便更改,args只是一个变量而已,但是约定默认使用的就是*args,建议不要更改

**kwargs

示例代码

def func(a,b,c,**kwargs):
    print(kwargs)
func(1,2,3,r=4,s=5)

执行结果

**kwargs只接收关键字参数

**kwargs动态传参,他将所有的关键字参数放到一个字典中,返回的结果是一个字典,从前往后找

示例

def func(a,b,c,**kwargs):
    print(kwargs)
func(1,2,3,r=4,b1=5,c1=6,d=7)

执行结果为

{'d': 7, 'c1': 6, 'r': 4, 'b1': 5}

**kwargs动态传参,他将所有的关键字参数(非位置对应的)放到一个字典中

示例

def func(a,b,c,**kwargs):
    print(kwargs)
func(1,2,r=4,b1=5,c1=6,c=7)

执行结果

{'c1': 6, 'b1': 5, 'r': 4}

**kwargs动态传参,他将所有的关键字参数(无意义的)放到一个字典中

上面示例中的c参数,是有意义的

最终顺序:位置参数,*args,默认参数,**kwargs

例子:

def func(a,b,c,d,*args,e='男',**kwargs):
    print(a)
    print(b)
    print(c)
    print(d)
    print(args)
    print(e)
    print(kwargs)
func(1,2,3,4,5,6,7,v=3,m=7,h=9,e='女')

执行结果

一般情况下,用这种方式就可以了

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

查看python源码

*魔法运用

例子

def func(*args):
    print(args)
l1 = [1,2,30]
l2 = [1,2,33,21,45,66]
func(*l1)
func(*l1,*l2)

执行结果

在函数的调用时,*代表打散

例子2

def func(*args):
    print(args)
l1 = [1,2,30]
l2 = [1,2,33,21,45,66]
tu = (1,2,3)
func(*l1,*l2,*tu)

执行结果

(1, 2, 30, 1, 2, 33, 21, 45, 66, 1, 2, 3)

*就相当于迭代添加

在函数的调用时,*可迭代对象,代表打散(list,tuple,str,dict(键))

比如用到要传多个列表时,需要用到魔法运用

def func(*args):
    print(args)
func(1,2,3,10,20,80)

执行结果

(1, 2, 3, 10, 20, 80)

在函数的调用执行时,*可迭代对象,代表打散

在函数定义时,*args代表的是聚合

将字典的键值对,添加到函数中

def func(**kwargs):
    print(kwargs)
dic1 = {'name1':'sam','age1':16}
dic2 = {'name2':'tom','age2':20}
func(**dic1,**dic2)

执行结果

{'age1': 16, 'age2': 20, 'name1': 'sam', 'name2': 'tom'}

**kwargs只限于字典

在函数的调用执行时,

*可迭代对象,代表打散(list,tuple,str,dict(键))将元素一一添加到args

**字典,代表打散,将所有键值对放到一个kwargs字典里

在函数定义时,*args,**kwargs代表的是聚合

def func(*args,**kwargs):
    print(args)
    print(kwargs)
dic1 = {'name1':'sam','age1':18}
dic2 = {'name2':'tom','age2':20}
func(*[1,2,3,4],*'abcdef',**dic1,**dic2)

执行结果

(1, 2, 3, 4, 'a', 'b', 'c', 'd', 'e', 'f') #打散

{'name1': 'sam', 'age1': 18, 'name2': 'tom', 'age2': 20} #聚合

我们首先回忆一下Python代码运行的时候遇到函数是怎么做的,从Python解释器开始执行之后,就在内存中开辟里一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的将函数名读如内存,表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。

  等执行到函数调用的时候,Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量回储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。

我们给这个‘存放名字与值的关系’的空间起了一个名字-------命名空间。

代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间;

在函数的运行中开辟的临时的空间叫做局部命名空间。

命名空间和作用域

命名空间一共分为三种

全局命名空间

局部命名空间

内置命名空间

内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法

三种命名空间之间的加载和取值顺序

加载顺序:内置命名空间(程序运行前加载)-->全局命名空间(程序运行中:从上到下加载)-->局部命名空间(程序运行中:调用时才加载)

例子

def my_len(argv):
    return 666
print(len([12,3]))

执行结果,因为函数没有被调用,所以直接打印len里面列表的长度

2   

取值顺序:

    在局部调用:局部命名空间-->全局命名空间-->内置命名空间

    在全局调用:全局命名空间-->内置命名空间

综上所述,在找寻变量时,从小范围,一层一层到大范围去寻找

例子

name = '张三'
def func():
    name = 'sam'
    print(name)
func()

执行结果,程序运行中,从上到下加载,name的值被局部命名空间里的值覆盖了

sam

例子2

a = 2
print(a)
def func():
    age = 11
    print(age)
func()

执行结果

2

11

例子3

print(111)
def func1():
    print(333)
def func2():
    print(444)
def func3():
    print(555)
    func2()
func1()
print(222)

执行结果,从上往下执行,首先打印111,中间遇到了几个函数,只是暂存到内存中,并不执行,后面调用func1,从而打印333,下面的几个函数没有调用,所以不执行,最后打印222

111

333

222

例子4

print(111)
def func1():
    print(333)
    func2()
    print(666)
def func2():
    print(444)
def func3():
    print(555)
func1()
print(222)

执行结果,先手打印111,遇到func1-3函数暂存到内存中,遇到调用func1函数,打印出333,然后调用func2,打印444,这里注意,要等func2执行完成后,才会执行func1后面剩余的print(666),最后打印222

111

333

444

666

222

例子5

def f1():
    def f2():
        def f3():
            print("in f3")
        print("in f2")
        f3()
    print("in f1")
    f2()

f1()

执行结果,调用f1,先打印'in f1'在调用f2,打印'in f2'在调用f3,打印'in f3'

in f1

in f2

in f3

作用域

作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域

全局作用域:包含内置名称空间,全局名称空间,在整个文件的任意位置都能被引用,全局有效

局部作用域:局部名称空间,只能在局部范围内生效

globals和locals方法

globals:全局名称空间:所有变量

locals:局部名称空间:所有变量

例子

a = 2
b = 3
def func1():
    c = 5
    d = 6
    print(globals()) #全局变量放在一个字典中
    print(locals()) #局部变量(函数里的c,d)放在一个字典中
func1()

执行结果

例子2

a = 3
b = 5
def func1():
    c = 6
    d = 8
    e = 10
    print(globals()) #全局变量放在一个字典中
    return locals()  #局部变量(函数里的c,d,e)放在一个字典中
print(func1())

如果逻辑比较多,可以使用return locals() 查看函数所有局部变量,返回字典类型

global关键字,nonlocal关键字

global:

1 声明一个全局变量

2 在局部作用域想要对全局作用域的全局变量进行修改时,需要用到global(限字符串,数字)

例子1

def func1():
    global name
    name = '你好'
    print(name)
func1()
print(name)

执行结果,在局部空间内,声明一个全局变量

你好

你好

例子2

name = '哈哈'
def func1():
    global name
    name = '你好'
func1()
print(name)

执行结果,因为函数func1里面声明使用全局变量name,对name的值进行了修改,所以最后打印的值是函数里面name的值

你好

例子3

def func1():
    global a
    a = 5
func1()
a = 4
print(a)

执行结果,代码从上至下执行,最后a=4把a的值覆盖了

4

对可变数据类型(list,dict,set)可以直接引用不用通过global

例子

li = [1,2,3]
dic = {'a':'b'}
def change():
    li.append('a')
    dic['q'] = 'g'
    print(dic)
    print(li)
change()
print(li)
print(dic)

执行结果,很明显,这里没有使用global声明,也可以直接添加

{'q': 'g', 'a': 'b'}

[1, 2, 3, 'a']

[1, 2, 3, 'a']

{'q': 'g', 'a': 'b'}

nonlocal

1 不能修改全局变量

2 在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用到哪层,从那层及父级或以下此变量全部发生改变。

错误例子

a = 4
def func1():
    nonlocal a
    a = 5
func1()
print(a)

执行报错

SyntaxError: no binding for nonlocal 'a' found

例子

def func1():
    b = 6
    def func2():
        nonlocal b #
        b = 666
        print(b)
    func2()
func1()

执行输出

666

例子2

def add_b():
    b = 42
    def do_global():
        b = 10
        print(b)
        def dd_nonlocal():
            nonlocal b
            b = b + 20
            print(b)
        dd_nonlocal()
        print(b)
    do_global()
    print(b)
add_b()

执行结果

10

30

30

42

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Laoqi's Linux运维专列

函数的变量+返回值

12740
来自专栏marsggbo

malloc函数及用法

动态存储分配 在数组一章中,曾介绍过数组的长度是预先定义好的,在整个程序中固定不变。C语言中不允许动态数组类型。 例如: int n; scanf("%d",&...

26180
来自专栏用户画像

正则表达式匹配 整数和正整数

?匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?

9820
来自专栏遊俠扎彪

C++中的字符数组、字符串、字符指针的一些笔记

1、sizeof会计算实际内存空间,strlen会计算C风格的字符串的实际字符数(不包括\0)。

201100
来自专栏Deep learning进阶路

C++随记(六)---函数处理数组的一些问题

C++随机(六)---函数处理数组的一些问题 本篇讨论数组做函数形参的情况。 通常,我们按照以往设置形参的习惯,可能会对数组形参做如下的书写: int exa...

18900
来自专栏PHP在线

PHP5常用函数

PHP已经更新到很多个版本,最近用的比较多的要数PHP5。下面我们为大家总结了PHP5常用函数,以便大家将来实际编写代码中查看。 pathinfo返回文件路径的...

48530
来自专栏Vamei实验室

Python基础04 运算

Python的运算符和其他语言类似 (我们暂时只了解这些运算符的基本用法,方便我们展开后面的内容,高级应用暂时不介绍) 数学运算 >>>print 1+9   ...

22780
来自专栏用户3030674的专栏

java映射(map用法)

主要分三类:集合(set)、列表(List)、映射(Map) 1.集合:没有重复对象,没有特定排序方式 2.列表:对象按索引位置排序,可以有重复对象 3.映射...

69320
来自专栏web

js中push(),pop(),unshift(),shift()的用法小结

12820
来自专栏深度学习之tensorflow实战篇

python中从str中提取元素到list以及将list转换为str

在Python中时常需要从字符串类型str中提取元素到一个数组list中,例如str是一个逗号隔开的姓名名单,需要将每个名字提取到一个元素为str型的list中...

42930

扫码关注云+社区

领取腾讯云代金券