1. 函数进阶

动态接收位置参数

之前写的函数都是固定参数的,假设有个函数需要的参数由几十个,一个个写在形参的位置会非常麻烦,因此我们要考虑使用动态参数,使用动态参数时需要在参数前加*,表示接收多个参数:

  1. In [13]: def func5(a, b, c, d, e, f):
  2. ...: print(a, b, c, d, e, f)
  3. In [14]: func5(1, 2, ,3 ,4 , 5, 6) # 按照之前的写法是在传参的时候参数的个数都是固定的
  4. 1 2 3 4 5 6
  5. In [18]: def func6(*args): # 使用动态接收参数后可以接收任个位置参数
  6. ...: print(args)
  7. In [19]:
  8. In [19]: func6(1, 2, 3 ,4 , 5, 6, 7, 8, 9, 10)
  9. (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
  10. In [20]:

从上面的例子我们可以看出,动态参数可以接收任意个参数,在形参中作为一个元组的形式传递过来;但是此时要注意的是:动态参数必须要在位置参数的后面:

  1. In [20]: def func7(*args, a, b):
  2. ...: print(args)
  3. In [21]: func7(1, 2, 3, 4)
  4. ---------------------------------------------------------------------------
  5. TypeError Traceback (most recent call last)
  6. <ipython-input-21-8171430efdb6> in <module>
  7. ----> 1 func7(1, 2, 3, 4)
  8. TypeError: func7() missing 2 required keyword-only arguments: 'a' and 'b'
  9. In [22]:

位置参数放在后面的时候,所有的参数都被args接收了,即a和b永远接收不到参数,因此动态参数必须在位置参数的后面

  1. In [22]: def func8(a, *args, b=100): # 正确使用方法
  2. ...: print(a, args, b)
  3. In [23]: func8(1, 2, 3, 4)
  4. 1 (2, 3, 4) 100
  5. In [24]: def func8(a, b=100, *args):
  6. ...: print(a, args, b)
  7. In [25]: func8(1, 2, 3, 4)
  8. 1 (3, 4) 2
  9. In [26]: func8(1, 2)
  10. 1 () 2
  11. In [27]: func8(1)
  12. 1 () 100
  13. In [28]:

从上面的例子可以看出,默认参数放在动态传参在之前时,只有在一种情况下才有效,即位置参数不够的情况下,会使用默认参数的值,那此时的动态传参也就没有意义了;所以只有当默认参数放在动态参数后面时,默认参数时永远生效的。

那么我们可以总结出动态传参的要注意的顺序:*位置参数, 动态参数, 默认参数

动态接收关键字参数

在python中使用*可以动态接收位置参数,但是这种方法并无接收关键字参数,在python中应该使用**来接收动态关键字参数

  1. In [28]: def func8(**kwargs):
  2. ...: print(kwargs)
  3. In [29]: func8(a='aaa', b='bbb')
  4. {'a': 'aaa', 'b': 'bbb'}
  5. In [30]:

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

  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])

2. 命名空间

我们用于存放变量名和其值的对应关系的空间,可以给它一个名字叫命名空间,我们的变量存储的时候就是存储在这片空间内的。

命名空间的分类

  • 全局命名空间:在单个py文件中,函数声明外的变量都属于全局变量都属于全局命名空间
  • 局部命名空间:在函数中声明的变量会存放在局部命名空间
  • 内置命名空间:python解释器内置的一些变量(如list,tuple,str,int等等)

命名空间的加载顺序

  • 内置命名空间
  • 全局命名空间
  • 局部命名空间

取值顺序

  • 局部命名空间
  • 全局命名空间
  • 内置命名空间
  1. In[2]: a = 10
  2. In[3]: def func1():
  3. ...: a = 20
  4. ...: print(a) # 函数内部有变量a,就优先取局部命名空间的变量
  5. ...:
  6. In[4]: func1()
  7. 20
  8. In[5]: print(a)
  9. 10
  10. In[6]:

作⽤域:

  • 作⽤域就是作⽤范围, 按照⽣效范围来看分为 全局作⽤域和局部作⽤域
  • 全局作⽤域: 包含内置命名空间和全局命名空间. 在整个⽂件的任何位置都可以使⽤(遵循

    从上到下逐⾏执⾏). 局部作⽤域: 在函数内部可以使⽤.

    作⽤域命名空间:
  1. 全局作⽤域: 全局命名空间 + 内置命名空间
  2. 局部作⽤域: 局部命名空间

    我们可以通过globals()函数来查看全局作⽤域中的内容, 也可以通过locals()来查看局部作

    ⽤域中的变量和函数信息
  1. In[7]: a = 10
  2. In[8]: def func():
  3. ...: a = 40
  4. ...: b = 20
  5. ...: def abc():
  6. ...: print("哈哈")
  7. ...: print(a, b) # 这⾥使⽤的是局部作⽤域 40,20
  8. ...: print(globals()) # 打印全局作⽤域中的内容
  9. ...: print(locals()) # 打印局部作⽤域中的内容
  10. ...:
  11. In[9]: func()
  • locals(): 查看当前作用域中的名字
  • globals(): 查看全局作用域中的名字

3. 关键字global和nonlocal

首先先介绍一下函数的嵌套:

  1. # 函数的嵌套,即函数里面定义函数,该函数只能在上层函数中使用
  2. def fun2():
  3. print(222)
  4. def fun3():
  5. print(666)
  6. print(444)
  7. fun3()
  8. print(888)
  9. print(33)
  10. fun2()
  11. print(555)
  12. # 打印结果:
  13. # 33
  14. #222
  15. # 444
  16. # 666
  17. # 888
  18. # 555

使用global关键字可以在局部作用域中把全局命名空间的变量拿过来用(可以修改),如果指定的变量不存在则创建。

  1. In[12]: a = 100
  2. In[13]: def func2():
  3. ...: global a # 此时这个函数中的a已经是全局变量a了
  4. ...: a = 78
  5. ...: print(a)
  6. ...:
  7. In[15]: func2()
  8. 78
  9. In[16]: a # 此时可以看到,a的值已经变成78了
  10. Out[16]: 78

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

  1. In[19]: a = 3
  2. In[20]:
  3. In[20]: def func3():
  4. ...: a = 9
  5. ...: def func4():
  6. ...: nonlocal a # 此时使用的就是func3中的a变量
  7. ...: a = 23 # 因此func3中的a被修改成了23
  8. ...: print(a)
  9. ...: func4()
  10. ...: print(a)
  11. ...: func3()
  12. 23 # 函数func4打印的结果
  13. 23 # 函数func3打印的结果
  14. In[21]: print(a)
  15. 3 # 最后函数结束打印的结果
  • global:把全局的内容引入到局部,如果全局命名空间没有这个变量,则创建这个变量而并不会报错
  • nonlocal:在局部, 把上一层的变量引入进内部. 如果上一层没有. 继续上一层;最外层函数中还没有时,会报错(不会再全局命名空间中查找)

python学习笔记:第10天 函数进阶和作用域的更多相关文章

  1. python学习笔记(10)函数(二)

    (函数的参数&递归函数) 一.函数的参数 Python的函数定义非常简单,但灵活度却非常大.除了正常定义的必选参数外,还可以使用默认参数.可变参数和关键字参数,使得函数定义出来的接口,不但能处 ...

  2. 【python学习笔记】10.充电时刻

    [python学习笔记]10.充电时刻 任何python都可以作为模块倒入 *.pyc:平台无关的经过编译的的python文件, 模块在第一次导入到程序中时被执行,包括定义类,函数,变量,执行语句 可 ...

  3. Deep learning with Python 学习笔记(10)

    生成式深度学习 机器学习模型能够对图像.音乐和故事的统计潜在空间(latent space)进行学习,然后从这个空间中采样(sample),创造出与模型在训练数据中所见到的艺术作品具有相似特征的新作品 ...

  4. Python学习笔记014——迭代工具函数 内置函数enumerate()

    1 描述 enumerate() 函数用于将一个可遍历的数据对象(如列表.元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中. 2 语法 enumerate(sequ ...

  5. python学习笔记十——模块与函数

    第五章 模块与函数 5.1 python程序的结构 函数+类->模块              模块+模块->包                 函数+类+模块+包=Python pyth ...

  6. Python学习笔记(九)—— 函数

    一.函数调用: 1.python内部函数查询:http://docs.python.org/3/library/functions.html#abs 2.注意调用函数的参数个数和类型. 3.函数名其实 ...

  7. python学习笔记-(十一)面向对象进阶&异常处理

    上篇我们已经了解了一些面向对象的基础知识,本次就了解下面向对象的一些进阶知识(虽然我也不知道有什么卵用). 静态方法 静态方法是一种普通函数,就位于类定义的命名空间中,它不会对任何实例类型进行操作.使 ...

  8. python学习笔记之迭代器和函数(第三天)

    一.collection系列: 1.counter计数器 如果counter(dict)是对字典的一个补充,如果counter(list)则是对列表的补充,初步测试对字典的值进行排序. ####### ...

  9. Python学习笔记-Day3-python内置函数

    python内置函数 1.abs    求绝对值 2.all 判断迭代器中的所有数据是否都为true 如果可迭代的数据的所有数据都为true或可迭代的数据为空,返回True.否则返回False 3.a ...

随机推荐

  1. Java学习-1

    数组 运算符 包 访问权限 修饰符 数组 1. 数组的声明: int[] a; 2. 数组的创建 使用new运算符数组的创建int[] a = new int[100] 数组的长度不要求是常量:new ...

  2. cocos2dx中node的pause函数(lua)

    time:2015/05/14 描述 lua下使用node的pause函数想暂停layer上的所有动画,结果没有效果 1. pause函数 (1)cc.Node:pause 代码: void Node ...

  3. Java学习---JFreeChart动态图表

    JFreeChart是Java中开源的制图组件,主要用于生成各种动态图表.在Java的图形报表技术中,JFreeChart组件提供了方便.快捷.灵活的制图方法.作为一个功能强大的图形报表组件,JFre ...

  4. Compare DML To Both REDO And UNDO Size

    SUMMARY you can remember undo rule  the same to redo if you want demo rule that you can look up the ...

  5. Asp.Net MVC Identity 2.2.1 使用技巧(五)

    创建用户管理相关视图 1.添加视图 打开UsersAdminController.cs   将鼠标移动到public ActionResult Index()上  右键>添加视图   系统会弹出 ...

  6. Python 处理脚本的命令行参数(二):使用click

    安装click pip install click 使用步骤 使用@click.command() 装饰一个函数,使之成为命令行接口 使用@click.option() 等装饰函数,为其添加命令行选项 ...

  7. 怎么知道是哪个div被点击了

    怎么知道是哪个div被点击了 不在div中加onclick等事件调用函数 ,用事件监听函数,但是如果div中的div被点击了,addEventListener得到了两个监听事件,我想点击div里的di ...

  8. BZOJ 1059 矩阵游戏 二分图匹配

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1059 题目大意: 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏 ...

  9. 洛谷 P4783 【模板】矩阵求逆

    题目分析 模板题. #include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod=1e ...

  10. gdbt与adboost(或者说boosting)区别

    boosting 是一种将弱分类器转化为强分类器的方法统称,而adaboost是其中的一种,或者说AdaBoost是Boosting算法框架中的一种实现 https://www.zhihu.com/q ...