python3函数详总结(语言尽量简洁)

之前学函数总觉都不系统,这次整理结合了太白金星的博客,但是是经过自己理解,精简语言之后的内容。

函数:

def f_name(p1, p2, *args, p3=None, p4, **kwargs):
	
	...##此处是函数体
	
	return 
	'''
	函数到return结束
		1、return后面无值,则函数执行到这里结束。
		2、return后面一个值,则返回这个值,函数结束。
		3、return后面你有多个返回值,则整体以一个元组的形式返回,可以在调用处使用结构接收返回值,函数结束。
	'''

调用处:

1、位置参数

f_name(p1, p2, p3)
'''
按照参数的先后顺序传递参数
'''

2、关键字参数

f_name(p3 = v1, p1 = v2, p2 = v3)
'''
按照参数的名字传参,不用考虑顺序(v1、v2和v3是参数值)
'''

3、两者结合使用:

f_name(p1, p3 = v3, p2 = v2)
'''
结合使用时,必须位置参数在前,关键字参数在后。
'''

实例:
def func(p1, p2, *args, p3=3, p4, **kwargs):
	
	print(p1, p2)
	print(args)
	print(p3, p4)
	print(kwargs)
	
	return 
	
func(1, 2, 3, 4, 5, p3=6, p4=7, a=1, b=2, c=3)
	
	
输出:
	1 2
	(3, 4, 5)
	6 7
	{'a': 1, 'b': 2, 'c': 3}
	

函数定义处参数(形参):

1、位置参数:
形如:p1, p2。只接收一个量的参数,比如一个整数,一个小数,一个字符串,一个列表,一个元组。。。

def f_name(p1, p2):
	...
	
	return 

2、默认值参数:
形如p3=3,即在定义时就给变量一个默认值,这个值在实参处若给出则默认值被覆盖,不给出则使用默认值

def f_name(p=3):
		...
		return
	1)f_name() #这样调用时p的值默认为3
	2)f_name(1) 或者 f_name(p=1) #这样调用时p的值为1

3、动态参数一,动态接收位置参数args:
形如
args,即在定义时加上号的参数,约定俗成一般使用args做参数名,即args,可以接受很多调用处的位置参数,并且将他们打包成元组(这里是因为*的“魔力”),传给args,且这种参数只能定义一个

def f_name(*args):
		print(args)
		return 
	f_name(1, 2, 3, 4)
	
	输出:
		(1,2,3,4)

4、动态参数二,动态接收关键字参数:
形如kwargs,即在定义时加上号的参数,约定俗成的一般使用kwargs做参数名,即**kwargs,可以接收很多调用处的关键字参数,并且把他们打包成字典,传给kwargs,且这种参数只能定义一个

def f_name(**kwargs):
		print(kwargs)
		return 
	f_name(a=1, b=2)
	
	输出:
		{'a': 1, 'b': 2}

5、python3新增参数类型,仅限关键字参数(不常用):
形如p4,定义在动态接受位置参数之后,动态接收关键字参数(若有的话)之前,和默认值参数没有位置约束。接收且必须以关键字形式接受一个实参

def f_name(*args, f3=3, f4):
		print(args)
		print(p3, p4)
		
		return 
	或者:
	def f_name(*args, f4, f3=3):
		print(args)
		print(p3, p4)
		
		return
	
	f_name(1, 2, 3, p3=4, p4=5)
	
	输出:
		(1, 2, 3)
		4 5

参数的顺序:

位置参数,动态接收位置参数args, 默认值参数, 【仅限关键字参数】, 动态接收关键字参数。
讨论:
首先位置参数肯定放在第一位的
然后动态接收位置参数
args和默认值参数谁在前呢? 肯定是args,假设默认值参数在前,如果使用位置传参数的话,本来想传给args的第一个参数会把默认值参数覆盖掉他的默认值。
之后是默认值参数和动态关键字参数谁在前呢?当然是默认值参数,假设**kwargs在前,则所有的关键字参数都会传给它,而默认值参数就永远该变不了默认值了。
最后仅限关键字参数是一定在
args和**kwargs中间的,它和默认值参数的顺序不受约束

*号的“魔力”:

*号的聚合和打散作用:
*号的聚合作用

刚刚我们说到的形参使用时,即args,会把传过来的位置参数打包成元组,传给args,这是一种聚合
还有**kwargs,会把传过来的关键字参数打包成字典传给kwargs

实例,聚合作用:
1)
def f_name(*args):
	print(args)
	return 
f_name(1, 2, 3, 4)

输出:
	(1,2,3,4)

2)
def f_name(**kwargs):
	print(kwargs)
	return 
f_name(a=1, b=2)

输出:
	{'a': 1, 'b': 2}

*号的打散作用:

另一种用法就是如果我们两个列表list1和list2,想把他们的元素传给*args怎么办到呢?
可以使用下面这种办法:

	def f1(*args):
		print(args)
		return


	l1 = [1, 2, 3]
	s1 = '456'
	f1(*l1, *s1)##对列表、字符串、元组等迭代类型都可以
	
输出:
	(1, 2, 3, '4', '5', '6')

另外一种情况,就是我们有两个字典d1和d2,想把他们的元素传给**kwargs怎么办到呢?
办法类似:

def f2(**kwargs):
	print(kwargs)
	return

d1 = {
		'a' : 1,
		'b' : 2
	}
	d2 = {
		'3' : 3,
		'4' : 4
	}
f2(**d1, **d2)

输出:

·{'a': 1, 'b': 2, '3': 3, '4': 4}

这是在函数传参数时,那么在函数外面呢?

函数外的聚合和打散:

**1、聚合(处理剩下的元素)**
我们这样用过:
	a, b = (1, 2)
我们还可以这样用:
  1)
	a, *b = [1, 2, 3, 4, 5]
	print(a, b)
  输出:
	1 [2, 3, 4, 5]
  2)
	*a, b = [1, 2, 3, 4, 5]
	print(a, b)
  输出:
	[1, 2, 3, 4] 5
	
**2、打散:**
	list1 = [1, 2, 3, 4, 5]
	print(*list1)
输出:
	1 2 3 4 5
#### 总结:即*可以用来将剩下的元素聚合到一起,也可以将一个迭代对象打散。非常灵活。

名称空间:

python在运行开始时会在内存中开辟一段空间,程序运行时遇到一个变量时就会把变量和值之间的关系记录下来;遇到函数定义时,只把函数名记录下来,不管函数内部的变量和逻辑。 只有当遇到函数调用的时候,python解释器会再开辟一块内存空间,用来存储函数的变量,且这些变量只能在函数内部使用,随着函数执行完毕,这块内存也会被清空。

全局命名空间:

我们称存储变量和值关系的空间为命名空间,程序开始时的命名空间为全局命名空间。

局部命名空间:

在函数运行时临时开辟的空间叫做局部命名空间,也叫临时名称空间

内置名称空间:

在python执行时有一些我们没有定义,却拿来即用的变量和函数,如input,print,list,str等,这些存放在内置命名空间中。

加载顺序:

首先在程序运行开始,内置名称空间内的东西是拿来即用的,肯定首先加载进来,然后遇到变量声明,函数定义,需要创建全局命名空间,之后每次遇到函数调用,都会为每个函数创建临时命名空间。所以加载顺序应该是:
内置命名空间 -->> 全局命名空间 -->> 临时命名空间1 -->>临时命名空间2 …

取值顺序:

取值顺序采取就近原则,从最近的命名空间一步步到最外面的命名空间,所以顺序为:
临时命名空间 -->> 全局命名空间 -->> 内置命名空间。

作用域:

作用域就是作用范围,分为全局作用域和局部作用域
全局作用域:全局命名空间+内置命名空间
局部作用域:局部命名空间

内置函数:

globals(): # 以字典的形式返回全局作用域所有的变量对应关系。

locals():  #以字典的形式返回当前作用域的变量的对应关系。

这里一个是全局作用域,一个是当前作用域,一定要分清楚,接下来,我们用代码验证:
# 在全局作用域下打印,则他们获取的都是全局作用域的所有的内容。

		a = 2
		b = 3
		print(globals())
		print(locals())
		'''
		{'__name__': '__main__', '__doc__': None, '__package__': None,
		'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001806E50C0B8>, 
		'__spec__': None, '__annotations__': {},
		'__builtins__': <module 'builtins' (built-in)>, 
		'__file__': 'D:/lnh.python/py project/teaching_show/day09~day15/function.py',
		'__cached__': None, 'a': 2, 'b': 3}
		'''

		# 在局部作用域中打印。
		a = 2
		b = 3
		def foo():
			c = 3
			print(globals()) # 和上面一样,还是全局作用域的内容
			print(locals()) # {'c': 3}
		foo()

改变变量的作用域:

#先看一个现象:
	a = 1
	def func():
		print(a)
	func()
	a = 1
	def func():
		a += 1 # 报错
	func()

也就是说全局变量在局部作用域不能做修改,只能读。

一、python提供了一个关键字可以实现在局部作用域对全局变量做修改:global

#1、global的第一个功能,使全局变量可以在局部作用域修改:
	count = 1
	def search():
		global count
		count = 2
	search()
	print(count)
#2、global的第二个功能是,声明一个全局变量:
	def func():
		global a
		a = 3
	func()
	print(a)

global的功能:

1、声明一个全局变量
2、在局部作用域修改全局变量,需要用global

二、python3新加的功能nonlocal(使用较少),功能和global类似,不过只对父级(且父级不能为全局作用域)作用域有效:

#例如:
		def add_b():
			##nonlocal b ##报错
			b = 42
			def do_global():
				b = 10
				print(b)
				def dd_nonlocal():
					nonlocal b
					b = b + 20
					print(b)
				dd_nonlocal()
				print(b)
			do_global()
			print(b)
		add_b()
#输出:
	10
	30
	30
	42

nonlocal功能:

1、不能更改全局变量
2、在局部作用域对父级作用域(或者更外层非全局作用域)的变量做修改,并且引用的哪层,从那层的及以下子层的变量全部发生改变。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章