Python基础(十)
今日主要内容
- 补充:传参与参数分配区别
- 动态传参
- 函数注释
- 名称空间
- 函数名的使用
- 函数嵌套
- global和nonlocal
补充:传参与参数分配区分
先看一个函数定义和函数调用
def func(a, b):
print(b, a) a = 5
b = 10
func(b, a) # 5 10

- 粉色箭头是传参的过程
- 青色箭头是分配参数的过程
传参的过程按照参数类型进行,位置参数按顺序一一对应传参,与变量名是什么无关
而参数分配是函数自己的事,函数体属于函数,分配参数的过程要按照变量名分配
一、动态传参
(一) 为什么要用动态传参
先来看一个例子:
- 定义一个吃饭的函数,每次调用时传入要吃的东西,打印菜单
def eat(zhushi, huncai, sucai, tang, tiandian):
print("我要吃:", zhushi, huncai, sucai, tang, tiandian) eat("大米饭", "红烧肉", "烧茄子", "番茄汤", "慕斯")
# 我要吃: 米饭 红烧肉 烧茄子 番茄汤 慕斯
- 这可能是我的饭量,但是这时来了一个女生,女生吃不了这么多啊,只选了一个小花卷,一盘黄瓜炒鸡蛋
def eat(zhushi, huncai, sucai, tang, tiandian):
print("我要吃:", zhushi, huncai, sucai, tang, tiandian) eat("小花卷", "黄瓜炒鸡蛋")
# TypeError: eat() missing 3 required positional arguments: 'sucai', 'tang', and 'tiandian'
- 由于我填入的参数与定义的参数数量不对应,调用时就会报错,怎么解决这个事情呢,这就要用到了我们的动态传参。
动态传参可以给函数传入不定量的参数,以元组、字典的方式打包起来,这就解决了我们填入参数是数量不定引发的error,下面我们来看看动态传参具体的方法
(二)两类动态传参
- 动态位置参数
- 动态关键字参数
动态位置参数(动态接收位置参数)
- 先来回忆一下位置参数,按照一一对应的位置来传参
def eat(zhushi, tang): # 按照位置接收参数(形参)
print(f"主食:{zhushi} 汤:{tang}") eat("米饭", "番茄蛋花汤") # 位置参数(实参)
# 主食:米饭 汤:番茄蛋花汤
- 动态接收位置参数,在形参前加一个星号
*,表示可接收任意数量的形参,以元组存储
def eat(*food): # 参数前加一个星号,表示动态接收位置参数
print(food) eat("米饭", "番茄蛋花汤") # 可以填写任意数量参数
# ('米饭', '番茄蛋花汤')
- 动态位置参数在python中一般用
*args来表示,只是一个行业内的规范,也可以用其他变量名定义但不建议使用
def eat(*args): # 一般用*args表示动态位置参数
print(args) eat("米饭", "番茄蛋花汤") # 可以填写任意数量参数
# ('米饭', '番茄蛋花汤')
结合之前两种形参(位置参数、默认值参数)共同分析
位置参数 + 动态位置参数
- 位置参数必须在动态位置参数前(位置参数 > 动态位置参数)
def eat(zhushi, *food):
print(zhushi, food) eat("米饭", "红烧肉", "排骨", "烧鸡")
# 米饭 ('红烧肉', '排骨', '烧鸡')
- 原因:如果动态位置参数(带星的)在前,那么所有实参全部都传给了动态位置参数(带星的),后面的位置参数(不带星的)是接收不到任何实参的,导致报错
def eat(*food, zhushi):
print(food, zhushi) eat("米饭", " 红烧肉", "排骨", "烧鸡")
# TypeError: eat() missing 1 required keyword-only argument: 'zhushi'
默认值参数 + 动态位置参数
- 默认参数必须在动态位置参数后( 动态位置参数 > 默认值参数)
def eat(*food, zhushi="米饭"):
print(food, zhushi) eat("回锅肉", "红烧肉", "翡翠白玉汤")
# ('回锅肉', '红烧肉', '翡翠白玉汤') 米饭- 原因:默认值参数的目的就是为了在重复输入情况下使用默认值,省去每次输入一样的参数,若默认值参数在前,则每次调用都需要填入参数,默认值参数就没有意义了
def eat(zhushi="米饭", *food):
print(zhushi, food) eat("米饭", "回锅肉", "红烧肉", "翡翠白玉汤") # 默认值参数没有意义
# 米饭 ('回锅肉', '红烧肉', '翡翠白玉汤')位置参数 + 默认值参数 + 动态位置参数
- 参数顺序:位置参数 > 动态位置参数 > 默认值参数
def eat(zhushi, *food, tang="番茄蛋花汤"):
print(zhushi, food, tang) eat("米饭", "红烧肉", "排骨", "烧鸡")
# 米饭 ('红烧肉', '排骨', '烧鸡') 番茄蛋花汤
动态关键字参数(动态接收关键字参数)
- 星号
*可以接收任意数量的位置参数,但是无法接收任意数量的关键字参数,在形参前加两个星号**就可以接受任意数量的关键字参数,以字典存储
def eat(zhushi, **cai):
print(f"主食:{zhushi} 菜:{cai}") eat("米饭", cai1="红烧肉", cai2="可乐鸡翅")
主食:米饭 菜:{'cai1': '红烧肉', 'cai2': '可乐鸡翅'}- 动态关键字参数在python中一般用
**kwargs来表示,只是一个行业内的规范,也可以用其他变量名定义但不建议使用
def eat(zhushi, **kwargs):
print(f"主食:{zhushi} 菜:{kwargs}") eat("米饭", cai1="红烧肉", cai2="可乐鸡翅")
主食:米饭 菜:{'cai1': '红烧肉', 'cai2': '可乐鸡翅'}- 星号
结合之前三种形参(位置参数、动态位置参数、默认值参数)共同分析
- 回想一下实参的顺序,给入实参时,位置参数必须要在关键字参数前,否则会报错
def func(a, b, c):
print(a, b, c) func(1, b=2, 3)
# SyntaxError: positional argument follows keyword argument- 所以关键字参数必须要在位置参数后,由于实参是这个顺序,所以形参在接收的时候也必须是这个顺序,所以动态关键字参数也必须在动态位置参数后
def eat(zhushi, *args, tang="番茄蛋花汤", **kwargs):
print(f"主食:{zhushi} 甜品:{args} 汤:{tang} 菜:{kwargs}") eat("米饭", "慕斯", "布丁", recai="可乐鸡翅", liangcai="大拌菜")
# 主食:米饭 甜品:('慕斯', '布丁') 汤:番茄蛋花汤 菜:{'recai': '可乐鸡翅', 'liangcai': '大拌菜'}形参的最终顺序:(重要)
- 位置参数 > 动态位置参数 > 默认值参数 > 动态关键字参数
星号
*的作用- 在函数定义的时候:聚合
- 动态位置参数聚合成元组
- 动态关键字参数聚合成字典
def func(a, b, *args): # 将我传入的3,4,5聚合成一个元组
print(a, b, args) func(1, 2, 3, 4, 5) # 1 2 (3, 4, 5)- 在函数调用的时候:打散
- 动态位置参数打散获取的是单个元素
- 动态关键字参数打散获取的是字典的键
def func(a, b, *args): # 将我传入的3,4,5聚合成一个元组
print(a, b, *args) # 将元组打散成元素输出 func(1, 2, 3, 4, 5) # 1 2 3 4 5无敌传参
- 可以传入任意类型参数、任意数量参数,无敌
def func(*args, **kwargs):
print(args, kwargs) func(1, 2, 3, k1=v1, k2=v2)
# (1, 2, 3) {'k1': 'v1', 'k2': 'v2'}
二、函数注释
(一)函数注释的好处
- 代码永远是写给人看的,在函数中添加注释可以让人清楚明了的了解函数的作用以及函数的用法
- 防止自己遗忘自己写的函数是干什么用的,当忘记的时候看注释就好了
- 可以在注释中明确变量以及返回值建议的数据类型
(二)注释用法
在函数体的第一行用多行注释
""" """,pycharm在函数中添加注释默认出现函数所用到的所有变量def func(args1, args2):
""" :param args1: int
:param args2: int
:return: int
"""
print(args1)
print(args2)
return args1, args2
在函数定义的时候,形参后面可以加冒号并写出建议传入的数据类型
def func(args1: int, args2: int):
"""
此处添加注释内容
:param args1: int
:param args2: int
:return: int
"""
print(args1)
print(args2)
return args1, args2
(三)关于函数的两个查看方法
查看函数的注释
函数名.__doc__,若无注释返回None
def func(args1, args2):
"""
进行加法运算
:param args1: int
:param args2: int
:return: int
"""
return args1 + args2 print(func.__doc__)运行结果: 进行加法运算
:param args1: int
:param args2: int
:return: int查看函数的名字
函数名.__name__
def func(args1, args2):
"""
进行加法运算
:param args1: int
:param args2: int
:return: int
"""
return args1 + args2 add = func
print(add.__name__) # 运行结果:func
三、名称空间(命名空间)
(一)什么是名称空间
- Python解释器开始执行之后,就会在内存中开辟了一个空间,每当遇到一个变量的时候,就会把变量名(内存地址)和值之间的关系记录下来,但是当遇到函数定义的时候,解释器只是把函数名(函数的内存地址)读入内存,表示这个函数存在了,而函数内部的变量和逻辑,解释器是不关心的,也就是说一开始的时候函数只是加载进来了,仅此而已,只有当函数被调用和访问的时候,解释器才会根据函数内部声明的变量开进行开辟变量的内部空间,随着函数执行完毕,这些函数内部变量占用的空间也会随着函数执行完毕被清空,我们给存放名字和值的关系的空间起一个名字叫:名称空间(命名空间),我们的变量在存储的时候就是存储在这片空间中的。(出自邱彦涛老师,我的偶像)
(二)名称空间的分类
- 在python中名称空间分为三部分:
- 内置空间
- 全局空间
- 局部空间
内置空间:存放python解释器为我们提供的名字,len、print、global等等
全局空间:用来存放py文件顶格运行时声明的变量
局部空间:用来存放在函数运行时声明的变量
名称空间加载顺序:
- 内置名称空间 > 全局名称空间 > 局部名称空间

变量取值顺序:
- 局部名称空间 > 全局名称空间 > 内置名称空间

(三)作用域
- 作用域就是作用范围,作用域分为两类:
- 全局作用域
- 局部作用域
全局作用域:整个文件的任何位置都可以使用
- 包含:内置名称空间 + 全局名称空间
globals()函数可以查看全局作用域中的变量和函数信息
a = 10
b = 20 def func(args1, args2):
print(args1)
print(args2)
print(globals())
return None func(30, 40)运行结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001B61F2786D8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/python_S26/day10/exercise.py', '__cached__': None, 'a': 10, 'b': 20, 'func': <function func at 0x000001B61D671EA0>}局部作用域:在函数内部可以使用
- 包含:局部名称空间
locals()函数可以查看当前作用域中的变量和函数信息(建议查看局部)
a = 10
b = 20 def func(args1, args2):
print(args1)
print(args2)
print(locals())
return None func(30, 40)运行结果:
30
40
{'args2': 40, 'args1': 30}
四、函数名的使用
(一)作为值
函数名可以当作值,赋值给另一个变量
def func():
print("zxd") name = func # 函数名赋值给另一个变量
print(func)
print(name)
name() 运行结果:
<function func at 0x000002161A261EA0>
<function func at 0x000002161A261EA0>
zxd
(二)作为参数
函数名可以当作另一个函数的参数来使用
def func():
print("zxd") def name(args):
print(args) # <function func at 0x00000299B5811EA0>
args() name(func) 运行结果:
<function func at 0x00000299B5811EA0>
zxd
(三)作为返回值
函数名可以当作另一个函数的返回值来使用
def name():
print("zxd") def func():
return name func()() 运行结果:
zxd
(四)作为容器中的元素
函数名可以当作元素存储在容器中
def login():
print("登录") def register():
print("注册") def look():
print("浏览商品") def buy():
print("购买商品") msg = """
1.注册
2.登录
3.浏览商品
4.购买商品
请选择序号:""" dic_func = {
"1": register,
"2": login,
"3": look,
"4": buy,
}
while True:
num = input(msg)
if num in dic_func.keys():
dic_func[num]()
else:
print("输入错误!")
五、函数嵌套
(一)交叉嵌套
函数参数作为另一个函数的参数,从而插入另一个函数中
看一个例子:
def func1(a):
print(1)
a()
print(2) def func2():
print(3)
re = func3()
print(re)
print(4) def func3():
print(5) func1(func2) 运行结果:
1 3 5 None 4 2运行顺序

(二)内部嵌套
函数内部嵌套函数
看一个例子
def func1():
print(1)
def func2():
print(2)
def func3():
print(3)
func3()
print(4)
func2()
print(5) func1() 运行结果:
1 2 3 4 5运行顺序

六、global和nonlocal
(一)global
全局中的变量在函数内部只有使用权,可以拿来用,但是不能更改
num = 10
def func():
num = num + 1
print(num) func()
print(num)
# UnboundLocalError: local variable 'num' referenced before assignment如果想在局部中修改全局变量,必须先用global声明要修改的全局变量
num = 10
def func():
global num
num = num + 1
print(num) # 11 func()
print(num) # 11在函数中使用了global声明了变量,但全局空间中并没有这个变量时,global会在全局空间中开辟这个变量
def func():
global num
num = 10
print(num) # 10 func()
print(num) # 10总结:
- 可以在局部空间修改全局空间的是变量
- 若全局空间无声明的变量则创建该变量
- global有效的控制因误操作在局部空间修改全局空间的变量
(二)nonlocal
nonlocal修改离nonlocal最近的上一层名称空间的变量,但只修改局部空间中的变量
num = 10
def func1():
num = 20
def func2():
num = 30
def func3():
nonlocal num
num += 1
print(num)
func3()
print(num)
func2()
print(num) func1()
print(num) 运行结果:
31 31 20 10nonlocal声明的变量如果是全局空间中的变量就会报错,并且nonlocal不会创建变量
num = 10
def func1():
def func2():
def func3():
nonlocal num # 局部空间内没有变量num
print(num)
func3()
print(num)
func2()
print(num) func1()
print(num) 运行结果:
SyntaxError: no binding for nonlocal 'num' found当前空间如果有变量,在去用nonlocal声明该变量,会报错,nonlocal只能声明上一层名称空间的变量
num = 10
def func1():
def func2():
def func3():
num = 10
nonlocal num #
print(num)
func3()
print(num)
func2()
print(num) func1()
print(num) 运行结果:
SyntaxError: name 'num' is assigned to before nonlocal declaration
Python基础(十)的更多相关文章
- python 基础(十) 面向对象
面向对象 一.概念 类(class): 用来描述具有相同属性和方法的对象的集合 对象是类的实例化 类变量:类变量在整个实例化的对象中是共用的.定义在类中 并且是函数体外的 实例变量:只能作用于 当前类 ...
- Python基础(十) __init__与__new__区别
__init__与__new__区别: __init__在python,其实是,在实例化之后执行的,用来初始化一些属性,相当于构造函数,但是又不一样 细心一些,通过参数会有所发现,其实__init__ ...
- Python基础(十二) 类私有成员和保护成员
python中的protected和private python中用 _var :变量名前一个下划线来定义,此变量为保护成员protected,只有类及其子类可以访问.此变量不能通过from XXX ...
- python基础十五之递归函数
递归函数,在函数中调用自身函数,就会形成一个递归函数.例如: def recursion(n): n += 1 print(n) recursion(n) 由于递归函数的结构,在函数调用时,它会一直调 ...
- python 基础(十五) socket编程
SOCKET TCP协议: 有请求 有响应 称之为 tcp协议 是面向连接的协议 就是在收发数据之前 必须先要建立一个可靠的链接 三次握手 如:网站 UDP协议: 是一个非链接的协议 传输之前不需要键 ...
- python 基础(十四) 正则表达式
正则表达式 概念: 正则匹配就是一个模糊的匹配 只要符合我的匹配规则 就会认为是正确的数据(精确的匹配) 1.[] #代表原子表把想要匹配的内容写入原子表中 匹配包含的任意一位字符 [a] ...
- python 基础(十二) 图片简单处理
pillow 图片处理模块 安装 pip install pillow pip是安装第三方模块的工具 缩放图片实例 from PIL import Image path = r'C:\Users\x ...
- python基础十四之匿名函数
匿名函数 处理简单问题的简化函数,关键字lambda. # 格式:函数名 = lambda 参数:返回值 anonymity = lambda s: s ** 0.5 print(anonymity( ...
- python基础十二之生成器进阶
生成器表达式 (满足条件的元素或其相关的操作 for 元素 in 可迭代对象 if 条件) g = (i for i in range(10)) for i in g: print(i) egg_li ...
- python基础十之装饰器
1,装饰器的形成 编程原则:开放封闭原则. 开放:对扩展是开放的 封闭:对修改是封闭的 因为修改是封闭的,所以为了对函数进行功能的扩展,就使用装饰器! 2,装饰器的定义 # wrapper就是一个装饰 ...
随机推荐
- 集合中Iterator迭代器的使用以及实现原理。
collection集合元素通用的获取方式,在取之前先要判断集合中有没有元素,如果有就把这个元素取出来,继续在判断,如果还有就再取出来,一直把集合中的元素全取出来,这种去出方式叫做迭代. 迭代器的作用 ...
- Appium+Python API相关知识了解
首先,要先了解,官方Appium API // https://testerhome.com/topics/3144 刚开始的时候,没有看官方API,然后在网上瞎找学习资料,发现python相关的很少 ...
- 如何美观地打印 Python 对象?这个标准库可以简单实现
前不久,我写了一篇文章回顾 Python 中 print 的发展历史 ,提到了两条发展线索: 明线:早期的 print 语句带有 C 和 Shell 的影子,是个应用程序级的 statement,在最 ...
- mybatis 源码分析(四)一二级缓存分析
本篇博客主要讲了 mybatis 一二级缓存的构成,以及一些容易出错地方的示例分析: 一.mybatis 缓存体系 mybatis 的一二级缓存体系大致如下: 首先当一二级缓存同时开启的时候,首先命中 ...
- 牛客网2016.4.11(两个数相加为sum/计数一个int型的二进制有多少个1/二叉树是否左右对称)
求最小的两个数相加为sum //求最小的两个数相加为sum public ArrayList<Integer> FindNumbersWithSum(int [] array,int su ...
- maven替换中央仓库,阿里云镜像下载及自定义本地仓库位置
maven替换中央仓库- 阿里云 在国内访问Maven仓库,下载速度太慢.下面是将中央仓库替换成阿里云的中央仓库的方法.国内还有其他的公共仓库,自己选择. 在你下载的maven版本-conf-set ...
- Django之静态文件,中间件,admin后台管理
静态文件 静态文件的使用 在 网页使用的css文件,js文件和图片等叫做静态文件.1)在项目下新建静态文件夹 static. 2) 配置静态文件所在的物理目录.Settings.py STATIC_U ...
- Python爬虫爬取全书网小说,程序源码+程序详细分析
Python爬虫爬取全书网小说教程 第一步:打开谷歌浏览器,搜索全书网,然后再点击你想下载的小说,进入图一页面后点击F12选择Network,如果没有内容按F5刷新一下 点击Network之后出现如下 ...
- 【原创】(二)Linux物理内存初始化
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- spss数据分析可以被人工智能替换吗
作为一名需要对课题进行研究的大学生,我在日常学习中经常需要用到spss,虽然老师上课已经初步教了我如何用这个软件,然而,在使用过程中我还是遇到了许多问题.具体来说,就是这个软件在很多地方都不够与时俱进 ...