Python自学之路之day09-函数的进阶

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

动态传参分为两种:

1、动态接收位置参数

  熟悉下之前说的位置传参:

def food(good_food,fruit):
    print("我要吃:",good_food,fruit)

food("米饭","西瓜")  # 按照位置顺序,把值传给函数对应的形参。

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

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

def food(*food):
    print("我要吃:",food)

food("米饭","西瓜")

打印结果:
我要吃: ('米饭', '西瓜')

结论:传递多个参数,会返回一个元祖。

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

## 错误位置参数
def
food(*food,fruit): print("我要吃:",food,fruit) food("米饭","小米","苹果")
打印结果:
程序会报错,因为前面传递进去的所有位置参数都被*food接收了furit永远接收不到参数

## 正确位置参数
def food(*food,fruit):
    print("我要吃:",food,fruit)

food("米饭","小米",fruit="苹果") ## 用关键字指定
打印结果:
我要吃: ('米饭', '小米') 苹果
### 但是这种写法,位置参数就不能⽤了,所以.我们要先写位置参数,然后再用动态参数
def food(fruit,*food):
print("我要吃:",fruit,food)

food("苹果","米饭","小米") # 前两个参数用位置参数来接收, 后面的参数用动态参数接收

 默认值与动态传参

def food(fruit,*food,drank="可乐"):
    print("我要吃:",fruit,food,drank)

food("苹果")
food("苹果","米饭","小米")

打印结果:
我要吃: 苹果 ('米饭', '小米') 可乐
我要吃: 苹果 () 可乐

可以看到,默认值都生效了。

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

2、动态接收关键字参数

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

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

def fn(**kwargs):
    print(kwargs)

fn(a=1,b=2,c=3)
fn(a=1,b=2)

打印结果:
{'a': 1, 'b': 2, 'c': 3}
{'a': 1, 'b': 2}

通过结果我们可以发现,打印的结果为字典类型。

 最终函数顺序:位置参数 > *args > 默认值 > **kwargs

如果想接收所有的参数:

def fn(*args,**kwargs):
    print(args)
    print(kwargs)

fn("kele",a=1,b=2)

打印结果:
('kele',) {'a': 1, 'b': 2}

3、动态传参的另一种方式

def fn(*args):
    print(args)

lst = [1,2,4,6]
fn(lst[0],lst[1],lst[2],lst[3])
fn(*lst)  ##可以使用*把一个列表按顺序打散(结构)

s = "我不好说"  ## 字符串也可以

fn(*s)


打印结果:

(1, 2, 4, 6)
(1, 2, 4, 6)
('', '', '', '')

在实参位置上给一个序列,列表,可迭代对象前面加个*表示把这个序列按顺序打散.在形参的位置上的* 表示把接收到的参数组合成⼀个元组。

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

def fn(**kwargs):
    print(kwargs)

dic = {"a":"可乐","b":"许碧"}

fn(**dic)

 二、命名空间

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

例如:

def fn():
    a = 10
    print(a)

fn()

print(a)  ## 此时a已经不存在了

我们给存放名字和值的关系的空间起一个名字叫: 命名空间.我们的变量在存储的时候就是存储在这片空间中的

命名空间分类:

  1. 全局命名空间--> 我们直接在py文件中, 函数外声明的变量都属于全局命名空间
  2. 局部命名空间--> 在函数中声明的变量会放在局部命名空间
  3. 内置命名空间--> 存放python解释器为我们提供的名字, list, tuple, str, int这些都是内置命名空间
加载顺序:
  1. 内置命名空间
  2. 全局命名空间
  3. 局部命名空间(函数被执行的时候)
取值顺序:
  1. 局部命名空间
  2. 全局命名空间
  3. 内置命名空间
a = 20
def fn():
    a = 10
    print(a)
fn()

打印结果:
10

作用域: 作用域就是作用范围, 按照生效范围来看分为全局作用域和局部作用域.
全局作用域: 包含内置命名空间和全局命名空间.在整个文件的任何位置都可以使用(遵循从上到下逐行执行).
局部作用域: 在函数内部可以使用.

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

a =10
def fn():
    a = 40
    b = 20
    def fn1():
        print("哈哈")
    print(a,b)        # 这里使用的事局部作用域
    print(globals())  # 打印全局作用域中的内容
    print(locals())   # 打印局部作用域中的内容

fn()
##打印结果
40 20
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000194884285F8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/Django/PythonExercise/day10/01.py', '__cached__': None, 'a': 10, 'fn': <function fn at 0x0000019488321E18>}
{'fn1': <function fn.<locals>.fn1 at 0x0000019488500AE8>, 'b': 20, 'a': 40}

 三、函数嵌套

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

def fn3():
    print(333)
    def fn4():
        print(444)
    print(666)
    fn4()
    print(888)
print(333)
fn3()
print(555)

打印结果:
333
333
666
444
888
555
总结:注意函数的执行顺序

四、global和nonlocal

首先我们写这样一个代码:首先在全局声明一个变量, 然后再局部调用这个变量,并改变这个变量的值:

a = 100
def fn():
    global a # 加了个global表示不再局部创建这个变量了,而是直接使用全局的a
    a =28
    print("我在函数内部:",a)
fn()
print("我在函数外部:",a)

打印结果:
我在函数内部: 28
我在函数外部: 28

global表⽰. 不再使用局部作用域中的内容了了. 而改用全局作用域中的变量,若是内部出现该变量内容,则会修改并同步到外部。

lst = ["可乐","雪碧","美年达"]
def fn():
    lst.append("mayunyun") # 对于可变数据类型可以直接进行访问.但是不能改地址,就是不能赋值。
    print(lst)

fn()
print(lst)

nonlocal 表示在局部作用域中, 调用父级命名空间中的变量。

## 加nonlocal
a = 10 def fn1(): a =20 def fn2(): nonlocal a a = 30 print(a) fn2() print(a) fn1() 打印结果: 30 30

## 不加nonlocal
a = 10
def fn1():
a =20
def fn2():
a = 30
print(a)
fn2()
print(a)
fn1()
打印结果:
30
20

再看,如果嵌套了很多层,会是一种什么效果:

a = 1
def fn1():
    a = 2
    def fn2():
        nonlocal a
        a = 3
        def fn3():
            a = 4
            print(a)
        print(a)
        fn3()
        print(a)
    print(a)
    fn2()
    print(a)

print(a)
fn1()
print(a)

打印结果:
1
2
3
4
3
3
1
注意分析,各个打印值对应的print。

 

posted @ 2019-08-15 17:56  小哥boy  阅读(57)  评论(0)    收藏  举报