函数参数相关&名称空间


函数参数部分

1. 函数参数的两大分类

1.1 形式参数

定义:指在函数 定义阶段 括号内所填写的参数,简称 形参

def func(a, b):
	pass
## a 和 b 就是func的形参。

1.2 实际参数

定义:指在函数 调用阶段 括号内所传入的参数,简称实参

def func(a, b):
	pass

func(1, 2)
# 数据 1和2 就是函数func的实参

1.3 注意!!

  1. 形参与实参的关系
    可以将形参看成是 变量名,实参看成是 变量值。
    两者在函数调用阶段,临时绑定,函数运行结束断开。

  2. 形参的表现形式只有一种:变量名。

  3. 实参的表现形式有多种(把握核心就是:数据值)

    1. 直接传入值
    2. 借助于变量名间接传入值
      m = 12
      n = 13
      func(m, n)
    3. 其他方法或者函数的返回值
      func(int('123'), int('456'))
      func(func1(), func2())-->将func1和func2的返回值当作参数传入。

2. 位置参数

位置参数:按照从左往右的顺序依次填入的参数。

位置形参 :函数定义阶段,括号内按照从左往右的顺序依次填入的变量名。

位置实参:函数调用阶段,括号内按照从左往右的顺序依次传入的变量值/数据值。

关键字实参(可以打破位置顺序)
在函数调用阶段,通过形参名= 数据值的形式,指名道姓的传值,打破位置参数的顺序。

# 定义一个比较大小的函数

def compare(a, b):  # a,b--位置形参
	if a > b:
		return a
	return b

res = compare(1, 2)  # 1,2--位置实参

# 关键字实参请注意
res = compare(11, a=33)  # 11,33都会传给a,这种情况是不可以出现的,报错。
res = compare(b=22,11)  # 位置参数必须要在关键字参数的前面,报错。

"""格式越简单的越靠前,后面一样适用。"""

tips:

  1. 位置形参 与 位置实参在函数调用阶段,按照位置一一对应绑定。
  2. 位置参数在绑定的时候,不能多也不景能少。

以上,为位置参数以及关键字参数内容所应该清楚的内容。


3. 默认参数

定义及特点:
默认参数--默认形参:函数在定义阶段就已经给形参赋值了。

  1. 该函数在调用阶段如果不给值,则使用默认的,
  2. 该函数在调用阶段也可以给值,则使用给的值。
    ps:当某一个值变化不是很大的时候可以用。

易错笔试题1:

# 默认形参 如果绑定的是一个列表,那么指向的是一个固定的地址

def func(name, age, hobby=[]):
	hobby.append(age)
	print('{}:{}:{}'.format(name, age, hobby))
	
func('jason',18)  # jason:18:[18]
func('duke',28)  # duke:28:[18,28]
func('jack',38)  # jack:38:[18,28,38]

# 可以这样解决
func('kk',22,[])  # 自己传入一个空列表
# 函数体中,每次结束前可以情况列表...等等一些方法。

易错笔试题2:

m = 200
def func(a, b, c=m):
	print(a, b, c)
	

m = 400
func(1, 2)  # 200
# 一定要注意
"""
如何去理解呢???
角度1
	默认形参在函数定义阶段就已经固定死了,不会随着后续的变化而变化。

角度2
	参考变量名与 值 的绑定关系在函数定义阶段,就已经将c与m=200所在地址进行绑定了,函数定义完成后,后面变量m与谁绑定都和参数c无关。
"""


4. 可变长参数(重点)

4.1 在形参中的用法

# 1. 函数无论传入多少 位置参数,都可以正常运行
def func1(*args):
	print(args)

func1(1,2,3,4,5)
"""
*号在形参中的使用
	用于接收 多余的 位置参数 ,并组织成 元组 的形式,
	赋值给*号后面的变量名。
"""
# 2. 函数无论传入多少 关键字参数,都可以正常运行
def func2(**kwargs):
	print(kwargs)

func(a=1, b=3, c=8)
"""
**号在形参中的使用
	用于接收多余的 关键字参数,并组织成 字典 的形式,
	赋值给**号后面的变量名。
"""

# 3. 定义一个函数无论传入多少位置参数和关键字参数都可以正常运行

def multiple(*args, **kwargs):
	print(args, kwargs)
	
multiple()  # (){}

"""
一般:
	可变长形参 *与** 后面的变量名其实是可以随便定义的,
	但是python中推荐使用
	*args --> arguments
	**kwargs --> keyword arguments
"""

4.2 在实参中的用法

def index(a, b, c):
	print(a, b, c)

new_list = [1,2,3,4]

index(*new_list)

"""
*号在实参中的使用
	会将列表,元组内的元素打散成位置参数的形式一一传值。

同理:
**号在实参中的使用
	会将字典内的键值对打散成关键字参数的形式一一传值。
"""

5. 函数参数补充(作为了解,几乎用不到)

5.1 命名关键字参数

def register(name, age, *, sex, height):  # sex,height为命名关键字参数
	pass

def register(name, age, *args, sex, height):
	pass

register('jason',11,sex='male',height='180cm')

"""
sex,height在传入实参的时候必须以关键字参数的形式
...该类型的参数几乎不用,也几乎很少遇到。
"""

def register1(name, age, *args, sex='male', height):  # sex不是默认参数,height也不是位置参数。


名称空间

什么是名称空间namespaces???
名称空间是用于存放变量名与变量值绑定关系的地方(类似民政局)

1. 名称空间的分类(重点!!!)

  1. 内置名称空间
python解释器提前给定义好的
print()
len()
...
  1. 全局名称空间
所有在py文件中顶格写的代码运行之后都会存入全局名称空间,如下:
name = 'xxx'  # name全局

def func():  # func全局
	pass

if 1:
	a = 123  # a全局

for i in range(10):
	print(i)

while True:
	b = 123
  1. 局部名称空间
    函数体代码运行之后产生的都是局部名称空间。

2. 存活周期的不同

  1. 内置名称空间
    随着python解释器启动与关闭而创建和销毁

  2. 全局名称空间
    随着py文件的运行和结束而创建和销毁

  3. 局部名称空间
    随着函数体代码的执行与结束而创建和销毁

3. 名字的查找顺序

len = '这是全局的len'

def index():
	len = '这是局部的len'
	print(len)

index()  # 这是局部的len

局部的嵌套

x = 11
def f1():
	x = 22
	def f2():
		x = 33
		def f3():
			x = 44
			def f4():
				x = 55
				print(x)
			f4()
		f3()
	f2()

# 通过调用f1,执行所有的函数
f1()  # 55

笔试题:

x = 11
def f1():
	x = 22
	def f2():
		x = 33
		def f3():
			x = 44
			def f4():
				print(x)
				x = 55
			f4()
		f3()
	f2()

f1()  # 结果会报错。。。

结论:

# 在查找名字的时候,要先确定自己当前在哪里
	1. 如果你在局部
		局部>>>全局>>>内置
	
	2. 如果你在全局
		全局>>>内置

# 查看名字是否在函数体内部,注意特例:上面的笔试题。。。