python函数(二)

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

  之前我们说过了传参,如果我们需要给一个函数传参,而参数又是不确定的,或者我给一个函数传很多参数,我的形参就要写很多,很麻烦,怎么办呢.我们可以考虑使用动态参数.

  形参的第三种:动态参数

  动态参数分成两种:

  1.动态的接收位置参数

  首先我们先回顾下位置参数,位置参数,按照位进行传参  

1 def chi(quality_food, junk_food):
2     print("我要吃", quality_food, junk_food)
3 chi("大米饭", "小米饭") # "大米饭"传递给quality_food "小米饭"传递给junk_food
4 按照位置传

   现在问题来了.我想吃任意的食物,数量是任意的,食物也是任意的.这时我们就要用到动态参数了.

 在参数位置编写*表示接收任意内容

1 def chi(*food):
2  print("我要吃", food)
3 chi("大米饭", "小米饭")
4 结果:
5 我要吃 ('大米饭', '小米饭') # 多个参数传递进去,收到的内容是元组tuple

动态接收参数的时候要注意:动态参数必须在位置参数后面

1 def chi(*food, a, b):
2   print("我要吃", food, a, b)
3 chi("大米饭" "小米饭" "黄瓜" "茄子")

这时候程序运行会报错.因为前面传递进去的所有位置参数都被*food接收了.a和b永远接收不到参数

所以必须改写成下面的代码

1 def chi(*food, a, b):
2  print("我要吃", food, a, b)
3 chi("大米饭", "小米饭", a="黄瓜", b="茄子") # 必须用关键字参数来指定

这个时候a和b就有值了,但是这样写位置参数就不能用了,所以我们要先写位置参数,然后再用动态参数

1 def chi(a, b, *food):
2   print("我要吃", a, b, food)
3 chi("大米饭", "小米饭", "馒头", "面条") # 前两个参数⽤位置参数来接收,后面的参数用动态参数接收

默认参数

1 def chi(a, b, c='馒头', *food):
2   print(a, b, c, food)
3 
4 chi("香蕉", "菠萝") # 香蕉 菠萝 馒头 (). 默认值生效
5 chi("香蕉", "菠萝", "葫芦娃") # 香蕉 菠萝 葫芦娃 () 默认值不生效
6 chi("香蕉", "菠萝", "葫芦娃", "口罩") # 香蕉 菠萝 葫芦娃 ('口罩',) 默认值不生效
7  

我们发现默认参数写在动态参数前面.默认值只有一种情况可能会生效.

1 def chi(a, b, *food, c="娃哈哈"):
2   print(a, b, food, c)
3 
4 chi("香蕉", "菠萝") # 香蕉 菠萝 () 娃哈哈 默认值生效
5 chi("香蕉", "菠萝", "葫芦娃") # 香蕉 菠萝 ('葫芦娃',) 娃哈哈 默认值生效
6 chi("香蕉", "菠萝", "葫芦娃", "口罩") # 香蕉 菠萝 ('葫芦娃', '口罩') 娃哈哈 默认值生效

这个时候我们发现所有的默认值都生效了.这个时候如果不给出关键字传参.那么你的默认值永远都生效的.

 

顺序:位置参数,动态参数*,默认值参数

 

2.动态接收关键字参数

在python中可以动态的位置参数,但是*这种情况只能接收位置参数无法接收关键字参数.

在python中使用**来接收动态关键字参数

1 def func(**kwargs):
2   print(kwargs)
3 func(a=1, b=2, c=3)
4 func(a=1, b=2)
5 结果:
6 {'a': 1, 'b': 2, 'c': 3}
7 {'a': 1 'b': 2}

这个时候接收的是一个dict

 

顺序的问题,在函数调用的时候,如果先给出关键字参数,则整个参数列表会报错

1 def func(a, b, c, d):
2   print(a, b, c, d)
3 # 关键字参数必须在位置参数后⾯, 否则参数会混乱
4 func(1, 2, c=3, 4)

所以关键字参数必须在位置参数后面,由于实参是这个顺序.所以形参接收的时候也是这个顺序,也就是说位置参数必须在关键字参数前面,动态接收关键字参数也要在后面

 

最终顺序:

位置参数>*args>默认值参数>**kwargs

这四种参数可以任意的进行使用.

 

如果想接收所有的参数:

1 def func(*args, **kwargs):
2   print(args, kwargs)
3 func("麻花藤","马云",wtf="胡辣汤")

 动态参数的另一种传参方式(打散):

1 def fun(*args):
2   print(args)
3 lst = [1, 4, 7]
4 fun(lst[0], lst[1], lst[2])
5 fun(*lst) # 可以使用*把一个列表按顺序打散
6 s = "臣妾做不到"
7 fun(*s)  字符串也可以打散 (可迭代对象)

在实参位置上给一个序列,列表,可迭代对象前面加个*表示把这个序列按顺序打散.

在形参位置上的*表示把接收到的参数组合成一个元组

如果是一个字典,那么也可以打散.不过需要用两个*

1 def fun(**kwargs):
2   print(kwargs)
3 dic = {'a':1, 'b':2}
4 fun(**dic)

函数的注释

1 def chi(food, drink):
2   """ 这里是函数的注释, 先写一下当前这个函数是干什么的, 比如我这个函数就是一个吃
3 :param :param food: 参数food是什么意思
4  :param :param drink: 参数drink是什么意思
5  :return :return: 返回的是什么东东
6   """
7   print(food, drink)
8   return "very good"

二.命名空间

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

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

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

命名空间一共分为三种:

  全局命名空间

  局部命名空间

  内置命名空间

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

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

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

取值顺序:

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

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

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

作用域

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

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

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

global关键字,nonlocal关键字。

global:

  1,声明一个全局变量。

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

复制代码
 1 def func():
 2     global a
 3     a = 3
 4 func()
 5 print(a)
 6 
 7 
 8 count = 1
 9 def search():
10     global count
11     count = 2
12 search()
13 print(count)
14 
15 global关键字举例
复制代码

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

复制代码
 1 li = [1,2,3]
 2 dic = {'a':'b'}
 3 
 4 def change():
 5     li.append('a')
 6     dic['q'] = 'g'
 7     print(dic)
 8     print(li)
 9 change()
10 print(li)
11 print(dic)
12 
13 对于可变数据类型的应用举例
复制代码

nonlocal:

  1,不能修改全局变量。

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

复制代码
 1 def add_b():
 2     b = 42
 3     def do_global():
 4         b = 10
 5         print(b)
 6         def dd_nonlocal():
 7             nonlocal b
 8             b = b + 20
 9             print(b)
10         dd_nonlocal()
11         print(b)
12     do_global()
13     print(b)
14 add_b()
15 
16 nonlocal关键字举例
复制代码

三.函数的嵌套

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

  2.函数的执行顺序

函数的嵌套调用

复制代码
 1 def max2(x,y):
 2     m  = x if x>y else y
 3     return m
 4 
 5 def max4(a,b,c,d):
 6     res1 = max2(a,b)
 7     res2 = max2(res1,c)
 8     res3 = max2(res2,d)
 9     return res3
10 
11 # max4(23,-7,31,11)
12 
13 函数的嵌套调用
14 
15 函数的嵌套调用
复制代码

函数的嵌套定义

复制代码
 1 def f1():
 2     print("in f1")
 3     def f2():
 4         print("in f2")
 5 
 6     f2()
 7 f1()
 8 ###########
 9 def f1():
10     def f2():
11         def f3():
12             print("in f3")
13         print("in f2")
14         f3()
15     print("in f1")
16     f2()
17     
18 f1()
19 
20 函数的嵌套定义
复制代码

函数的作用域链:小范围作用域可以使用大范围的变量,但是反之不行,他是单向的。

复制代码
def f1():
    a = 1
    def f2():
        def f3():
            print(a)
        f3()
    f2()

f1()
################
def f1():
    a = 1
    def f2():
        a = 2
    f2()
    print('a in f1 : ',a)

f1()

作用域链应用举例
复制代码

 

posted @   一二九  阅读(232)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示