函数
引子:
求1-15的和
求23-36的和:
求55-68的和:
用普通的方法就要循环求和,代码大部分地方都是重复的。而使用函数能简洁代码。
def sumxy(x, y):
sum = 0
for i in range(x, y + 1):
sum += i
return sum
print(sumxy(1, 15)) #120
print(sumxy(23, 36)) #413
print(sumxy(55, 68)) #861
函数于程序而言,是对程序逻辑进行结构化或者过程化的一种编程方式。
函数的定义
声明函数的一般形式:
def 函数名(arg1,arg2,...,argn):
函数内容
return 返回值
1.函数代码块以 def 关键词开头,后接函数标识符名称和小括号 ()。
2.任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
3.函数的第一行语句可以选择性地使用文档字符串----用于存放函数说明。
4.函数内容以冒号起始,并且缩进。
5.return [表达式] 结束函数,选择性的返回一个值给调用方。不带表达式的return相当于返回 None。
其中参数列表和返回值不是必须的,return后也可以不跟返回值,甚至连 return也没有。
对于return后没有返回值的和没有return语句的函数都会返回None值
有些函数可能既不需要传递参数,也没有返回值。
没有参数时,包含参数的圆括号也必须写上,圆括号后也必须有“:”。
函数参数种类
形参和实参
- 形参
- 只有在调用时才分配内存单元。调用结束后,即释放所分配的内存担忧。因此,形参只有内部有效,函数调用结束返回主调用函数后则不能再使用该形参变量
def kon(x,y): #x,y就是形参
return x,y
kon(1,2)
print(x)
#NameError: name 'x' is not defined
- 实参
- 实参是一个确定的值,能够传递给形参。
- 作为位置参数或者关键字参数传递
- 实参是一个确定的值,能够传递给形参。
def kon(x,y,z):
print('x',x)
print('y',y)
print('z',z)
kon(1,2,3)
#x 1
#y 2
#z 3
只传递实参,位置一一对应,也可以对其进行赋值
def kon(x,y,z):
print('x',x)
print('y',y)
print('z',z)
kon(y=1,z=2,x=3)
#x 3
#y 1
#z 2
注意:关键字参数必须在默认参数后面,否则报错
demo:
def kon(x,y):
return x,y
print(kon(1,y=2))
#(1, 2)
print(kon(y=2,x=1))
#(1, 2)
print(kon(x=1,2))
#SyntaxError: positional argument follows keyword argument
不定参数
在python中不定参数主要是指*args
和**kwargs
他们两主要是用于函数定义,我们可以将不定数量的参数传递给一个函数
*args
用来接收任意非键值对的
def uncertain_para(para, *args):
print("普通的位置参数:", para)
print('不定参数:', args)
print(type(args))
uncertain_para(1, 2, 3, 4, 'a', 'b')
uncertain_para([1,2,3],'ab')
-----------------
普通的位置参数: 1
不定参数: (2, 3, 4, 'a', 'b')
<class 'tuple'>
普通的位置参数: [1, 2, 3]
不定参数: ('ab', )
<class 'tuple'>
**kwargs
用于接收任意不定长度的键值对
def un_para_key(**kwargs):
print(kwargs)
print(type(kwargs))
un_para_key(a=1, b=2, c=3,d=7)
----------------------
{'a': 1, 'b': 2, 'c': 3, 'd': 7}
<class 'dict'>
函数属性
函数属性是python中另外一个使用了句点属性标识并拥有名字空间的领域
def foo():
'foo()-------- get string'
def bar():
pass
bar.__doc__='Oops,forget the str above'
bar.version=0.1
函数的引用
定义之后直接就可以拿来使用,只要运行程序位置在函数之下即可。你可以获得每个 pyhon 模块,类,和函数中任意的名字空间。你可以在模块 foo 和 bar 里都有名为 x 的一个变量,,但是在将这两个模块导入你的程序后,仍然可以使用这两个变量。所以,即使在两个模块中使用了相同的变量名字,这也是安全的,因为句点属性标识对于两个模块意味了不同的命名空间,比如说,在这段代码中没有名字冲突:
def foo(x):
x=3
return x
def bar(x):
x=9
return x
x=6
print(foo(x),bar(x),x)
#3 9 6
变量作用域
在python中,只有当变量在module,class,函数中定义的时候,才会有作用域的概念
def foo():
a='foo'
print(a)
foo()
print(a)
在作用域中定义的变量,一般只在作用域中生效。
作用域的类型
python中,使用一个变量并不要求需要预先声明它。但是在真正使用时,它必须绑定到某个内存对象,也就是说被定义、赋值。这种变量名的绑定将在当前作用域引入新的变量,同时屏蔽外层作用域中的同名变量
-
局部作用域(locale—L)
- 包含在def关键字定义的语句块中,即在函数中定义的变量。每当函数被调用时都会创建一个新的局部作用域。Python中也有递归,即自己调用自己,每次调用都会创建一个新的局部命名空间。在函数内部的变量声明,除非特别的声明为全局变量,否则均默认为局部变量。有些情况需要在函数内部定义全局变量,这时可以使用global关键字来声明变量的作用域为全局。局部变量域就像一个 栈,仅仅是暂时的存在,依赖创建该局部作用域的函数是否处于活动的状态。所以,一般建议尽量少定义全局变量,因为全局变量在模块文件运行的过程中会一直存在,占用内存空间。
注意:如果需要在函数内部对全局变量赋值,需要在函数内部通过global语句声明该变量为全局变量。
- 包含在def关键字定义的语句块中,即在函数中定义的变量。每当函数被调用时都会创建一个新的局部作用域。Python中也有递归,即自己调用自己,每次调用都会创建一个新的局部命名空间。在函数内部的变量声明,除非特别的声明为全局变量,否则均默认为局部变量。有些情况需要在函数内部定义全局变量,这时可以使用global关键字来声明变量的作用域为全局。局部变量域就像一个 栈,仅仅是暂时的存在,依赖创建该局部作用域的函数是否处于活动的状态。所以,一般建议尽量少定义全局变量,因为全局变量在模块文件运行的过程中会一直存在,占用内存空间。
-
嵌套作用域(enclosing—E)
-
包含在def关键字定义,E和L是相对的,E相对于跟上层的函数而言也是L。与L的区别在于,对于一个函数而言,L是定义在此函数内部定义的函数的局部作用域。
-
主要为了实现python的闭包
-
demo:
-
def a(): def b: return('局部作用域') #函数里的函数的作用域是局部作用域 return('嵌套作用域') #函数里有多层函数的是嵌套作用域,当然它对外层也是一个局部作用域
-
-
全局作用域(global—G)
- 在模块层次中定义的变量。模块顶层声明的变量具有全局作用域。从外部来看,模块的全局变量就是一个模块对象的属性。
-
内置作用域(built—B)
- 系统固定模块中定义的变量
搜素变量名的优先级:局部作用域>嵌套作用域>全局作用域>内置作用域
a=168
def foo():
a=23 #a=23 #若将这句注释就会出现问题,下一句print里优先搜索该函数的变量a
print(a) #但是此时a还未赋值,就会UnboundLocalError: local variable 'a' referenced before assignment
a=888
print(a)
def bar():
print(a)
foo()
bar()
----------
23
888
168
全局变量和局部变量
在函数、class、module里的变量即是局部变量。
能在单个程序中所有地方都可以调用的变量即是全局变量
gbl_str='pow' #全局变量
def power():
loc_str='er' #局部变量
return gbl_str+loc_str
print(power())#power
print(gbl_str)#pow
print(loc_str)#NameError: name 'loc_str' is not defined