函数定义和调用
函数定义
函数是:组织好的,可重复使用的,用来实现单一或相关联功能的代码段。
在程序中,函数的使用能提高应用的模块性、代码的重用率和可读性。
自定义函数的一般格式为:
def 函数名([参数1,参数2,...]):
"""函数说明"""
函数体
其中:
(1)函数关键字:def 函数名()
(2)函数名:遵循标识符命名规则,最好是有意义的名称,增加可读性
(3)参数:必须放在圆括号中间,称为形式参数(形参)。形参是可选的,可以没有,也可以有多个。
当有多个形参时,各形参之间用逗号隔开
(4)函数说明:函数第一号语句可以选择性的使用文档字符串,用于存放函数说明
(5)函数内容:以冒号起始,并且缩进
(6)返回值:使“return [表达式]”结束函数,返回一个值给调用方。
如果没有“return [表达式]”,函数默认返回None。当函数返回多个值时,其本质是把这些值作为一个元组返回。
如语句“return 2,6,8”,实际上返回的是元组(2,6,8)
a,b,c=2,6,8
a,b,c=(2,6,8)
a,b,c=[2,6,8]
a,b,c={
2:1,6:2,8:3}
"以上结果均为:a 2 b 6 c 8"
a,b,c={
2,6,8}
"该结果在该进程内随机"
a,b,c=268
"TypeError: cannot unpack non-iterable int object"
定义一个名为myHello()的函数
#定义函数
def myHello():
return "Hello, everyone!"
a=myHello()
print(a+"\n"+myHello())
"""
Hello, everyone!
Hello, everyone!
"""
例:函数成员的使用
def f():
a=0
print(a,b)
f() # ERROR:no b
b=1
f() # 0 1
del b
f() # ERROR:no b
del a # ERROR:no a
这里其实就是函数变量,话说之前无论是啃书还是啃文档,接触过了很多的函数内容了,这里其实就是函数内局域变量与全局变量的关系,关键在于主体下使用del删除局部变量无效。
其实即便有个语法真能del a,但是除非他并行运算,不然没有意义。
函数就是在调用的时候,才开辟并激活,不调用的时候不存在的东西。所以删除一个不存在的东西,自然不成功。
函数调用
函数定义完成后,就可以在程序中调用了。函数调用时,需要指出函数名称,并传入相应的参数。函数调用时传入的参数称为实际参数(实参)。在默认情况下,函数调用时传入的实参个数、顺序等必须和函数定义时形参的个数、顺序一致。
函数调用时的执行顺序如下:
(1)执行函数调用前的语句
(2)执行函数调用,运行被调用函数内的语句,并返回相应结果
(3)执行函数调用后的语句
PS:这里有个不是很恰当的描述,函数的形参定义,可以是预设数值的,但是预设数值需要在不预设数值的后面,一一对应的是没有预设值的形参,然后预设值的形参可选,可以顺序传入,也可以表达式传入。
python - 官方简易文档篇(1)常用、函数 详见函数部分
例:定义一个求梯形面积函数并调用
def echelonArea(top,bottom,height):
area=1/2*(top+bottom)*height
return area
if __name__=="__main__":
t=3.6;b=6.2;h=4.5
area1=echelonArea(t,b,h)
print("area1 =",area1)
area2=echelonArea # 这里是将函数的功能赋值给area2,area2就是这个函数的副本
print("area2 =",area2(t,b,h))
type(area2) # function
if __name__=="__main__":
name 是当前模块名,当模块被直接运行时模块名为 main 。这句话的意思就是,当模块被直接运行时,以下代码块将被运行,当模块是被导入时,代码块不被运行。
函数参数
参数传递
Python中的对象可分为不可变对象(数字、字符串、元组等)和可变对象(列表、字典、集合等)。
对应的,Python函数的参数传递有以下两种情况。
(1)实参为不可变对象。
当实参为不可变对象时,函数调用是将实参的值复制一份给形参。在函数调用中修改形参时,不会影响函数外面的实参。
(2)实参为可变对象。
当实参为可变对象时,函数调用是将实参的引用复制给形参。在函数调用中修改形参时,函数外面的实参也会随之变化。
a=0;b=1;l=[0,1]
def f(a,b,l):
a,b=b,a
l[0],l[1]=l[1],l[0]
f(a,b,l)
print(a,b,l)
# 0 1 [1,0]
参数类型
调用函数时可食用的正是参数类型包括:必须参数、关键字参数、默认参数和不定长参数。
1、必需参数
必需参数要求函数调用时传入的实参个数、顺序和函数定义时形参的个数、顺序完全一致。
def f(i,s,l):
"""i必须是int型,s必须是str型,l必须是list型"""
if type(i)==int:print("int")
else:print("ERROR")
if type(s)==str:print("str")
else:print("ERROR")
if type(l)==list:print("list")
else:print("ERROR")
f(10,"10",[10])
f(10,10,10)
help(f)
a=f.__doc__
print(a)
type(f.__doc__) # str
书上说:如果调用函数时的实参个数、顺序和函数定义时的形参个数、顺序不一致,运行时可能会得不到预期的结果。
个数不一致,直接报错。
以上我是用模拟的方法去规定了传递的参数的类型,而现实环境下,就是有传递过来后,会需要特定类型的运算,例如我就是要int,结果赋值或者未转化的原因,没有得到正确的运算甚至报错。
注释的调用方法 print(f.doc)
这里help(f)是和print一样打印出来的,但是f.__doc__却不是,他在jupyter中是与help(f)不在一起输出的,是另外一个单独的输出
在ipython中也是如此
在.py下运行,是不显示f.__doc__的
尽在python中正常显示
正常的直接运行.py的效果和IDLE下的python shell是一致的,都无法输出f.__doc__
我明白了,我突然就明白了,f.__doc__很单纯,他就是那串字符串,于是,python、ipython和jupyter都有显示变量、数值的效果,所以他们显示出来就是因为如此,而在显示运行环境下,f.__doc__就是一个单纯的变量。没有print自然就没有效果了!
关键字参数
关键字参数在函数调用时使用形参作为关键字来确定传入的参数值,允许函数调用时实参的顺序与函数定义是形参的顺序不一致。
这里有些无语,我觉得这个功能是为了让调用者知道自己是将什么数值赋值给什么变量。通常用于二次调用函数的请款下,这类函数属于之前写过甚至专门写出的,会有很多的参数,有个别必填的和多个选填的,因为不是这次写出的,所以哪些变量在那个位置上都不确定,所以使用关键字传递,而且某些不是必传的是有默认参数的,等。调入函数、查看函数文档、选择传递参数或关键字参数。如果一个公司里,关键字定义很严格的话,就可以直接用关键字传递参数,而不需要去看参数的先后顺序。
def rectangleArea(length,width):
return length*width
print(rectangleArea(length=10,width=2))
默认参数
调用函数时,如果没有传递实参,则会使用函数定义时赋予参数的默认值。
def CircleArea(radius,pi=3.141592653589793):
return 2*radius*pi
print(CircleArea(1))
print(CircleArea(1,3.141592654))
谁才是圆周率?π 和 τ 之间的战争
不定长参数
在实际应用中,有可能需要一个函数能处理比当初声明时更多的参数,这种参数称为不定长参数。不定长参数有如下两种形式:
(1)*args:将接受的多个参数放在一个元组中。
(2)**args:将显式赋值的多个参数放入字典中。
def mean(*args):
# return sum((*args,))
s=j=0
for i in (*args,):
s=s+i
j+=1
return s/j
print(sums(1,2,3)) # 6
def rank(**args):
"""变量名就是ID,数值是分数"""
l=[*args]
l.sort(key=lambda x:{
**args}[x],reverse=True) # 这里尝试用lambda去写,之前没有复习lambda来着,但是用法从来不是复习出来的,是用出来了,这里我开始就没有加reverse,但是因为是从小到大的顺序,所以排出来的并非正确名次,所以我让key的结果*-1,刚才才想起来还有reverse这个功能
for i in range(len(l)):
print("第%d名:%s"%(i+1,l[i]))
# print(a) ERROR
rank(a=1,b=2,c=3)
以上是错误演示,详见后面的最下边
平均数、中位数和众数及它们之间的关系
偶尔看到一位大佬的文章,线性回归,最小二乘法
*args的本质就是那些被打包的内容
例如1,2,3被打包成*args,那么*args就是1,2,3,没有引号,没有括号,传入到函数里,就是一个不是元组的元组,真要把他当作元组使用,需要(*args,)
同理,上面**args就是a=1,b=2,c=3,但是他传入函数时,也只是个不是字典的字典,真要当作字典调用,只需要{
arges}
那么他们传入函数的作用不是当作赋值,而是当作数据来处理。无法直接调用args,真的让函数内出现其传递的几个赋值表达式。
这里面有个例子,我改一下,或者说*与**的反向用法:
t=(1,2,3)
d={
"a":4,"b":5,"c":6}
def f(x1,x2,x3,a,b,c):
print(x1,x2,x3,a,b,c,sep="\n")
f(*t,**d)
#
1
2
3
4
5
6
*t是打包后的元组,这里有点迷,也就是说?一串数传递给*t,靠!我明白了~ 我一直搞错了!
def f(*t,**d):
print(t)
print(d)
f(1,2,a=3,b=4)
#
(1