MATLAB和Python除了使用内部提供的函数和第三方提供的函数外,还可以自己定义函数来实现一定的功能。自定义函数同样可以被反复调用,从而节省代码量并提高编程效率。[大谦MATLAB,dqmatlab点com]
函数定义格式
【MATLAB】
下面是自定义函数比较标准的格式,其中黑体加粗的文字表示自定义函数的基本组成部分:
function [x, y]=myfun(a, b, c) 函数定义行
% H1行——用一行文字来综述函数的功能
% 帮助文本——用一行或多行文本解释如何使用函数
% 在命令行中输入"help <functionname>"时可以使用它,对于主函数
% 函数体——一般从第一个空白行后开始。
% 注释 – 描述函数的行为,输入输出的类型等。
% 在命令行中输入"help <functionname>"时不会显示这些文本。
x=prod(a, b); %:开始编写函数代码
所以,一个完整的函数应该包括函数定义行、H1行、帮助文本、函数体、注释和函数代码等方面的内容,其中函数定义行和函数代码是必需的。
【Python】
Python中自定义函数的语法格式为:
def functionname(parameters):
"函数说明文档"
函数体
return [表达式]
其中,def和return是关键字,functionname为函数名,parameters为参数列表。注意小括号后面有1个冒号。冒号后面第1行添加注释,说明函数的功能,可以使用help函数进行查看。函数体各语句用代码定义函数的功能。def关键字打头,return语句结束,有表达式时返回函数的返回值,没有表达式时返回None。
函数定义好后,可以在模块中其他位置进行调用,调用时指定函数名和参数,如果有返回值,指定引用返回值的变量。
没有返回值的情况
函数可以没有参数,也可以没有返回值。下面定义1个函数,用一连串的星号作为输出内容的分隔行。定义该函数后进行3种运算,并在输出结果时调用该函数绘制星号分隔行分隔各种运算结果。
【MATLAB】
在MATLAB中新建脚本文件startline.m,文件代码为:
a=1;b=2;
sprintf("a=%d,b=%d",a,b)
sprintf("a+b=%d",a+b)
startline0 %第1次调用startline0函数
sprintf("a-b=%d",a-b)
startline0 %第2次调用startline0函数
sprintf("a*b=%d",a*b)
function startline0()
disp("**********");
end
运行脚本,在命令窗口输出以下结果。
>> startline
ans=
"a=1,b=2"
ans=
"a+b=3"
**********
ans=
"a-b=-1"
**********
ans=
"a*b=2"
可见,函数定义好以后,可以进行重复调用,提高编程效率。
【Python】
在Python IDLE中新建脚本文件sam14-001.py,文件中的代码为:
def starline(): #定义starline函数,绘制星号分隔行
"星号分隔行" #函数的功能说明
print('*x27;*40) #输出40个*
return
a=1;b=2
print('a={},b={}'.format(1,2))
print('a+b={}'.format(a+b)) #对两个数作加法运算
starline() #调用starline函数绘制分隔行
print('a={},b={}'.format(1,2))
print('a-b={}'.format(a-b)) #对两个数作减法运算
starline() #调用starline函数绘制分隔行
print('a={},b={}'.format(1,2))
print('a*b={}'.format(a*b)) #对两个数作乘法运算
help(starline) #输出starline函数的功能说明
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,则IDLE命令行窗口显示下面的结果:
>>> =RESTART: …/Samples/ch14/sam14-001.py
a=1,b=2
a+b=3
****************************************
a=1,b=2
a-b=-1
****************************************
a=1,b=2
a*b=2
Help on function starline in module __main__:
starline()
星号分隔行
可见,函数定义好以后,可以进行重复调用,提高编程效率。最后显示了starline函数的功能说明。
有一个返回值的情况
上面定义的starline函数没有参数,也没有返回值。下面定义一个mysum函数,对两个给定的数求和。该函数有2个输入参数和1个返回值。
【MATLAB】
在MATLAB中新建脚本文件mysum.m,文件代码为:
sprintf("3+6=%d",mysum0(3,6)) %计算和输出3和6的和
sprintf("12+9=%d",mysum0(12,9)) %计算和输出12和9的和
function s=mysum0(a,b) %求和
%求两个数的和
s=a+b;
end
运行脚本,在命令窗口输出以下结果。
>> mysum
ans=
"3+6=9"
ans=
"12+9=21"
【Python】
在Python IDLE中新建脚本文件sam14-002.py,文件中的代码为:
def mysum(a,b): #求和
"求两个数的和"
return a+b
print('3+6={}'.format(mysum(3,6))) #计算和输出3和6的和
print('12+9={}'.format(mysum(12,9))) #计算和输出12和9的和
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,则IDLE命令行窗口显示下面的结果:
>>> =RESTART: …/Samples/ch14/ sam14-002.py
3+6=9
12+9=21
有多个返回值的情况
函数有多个返回值时,也可以将这多个返回值添加到数组中,返回该数组。
【MATLAB】
在MATLAB中新建脚本文件mycomp.m,文件代码为:
[c,d]=mycomp0(2,3); %调用mycomp0函数,计算2和3的和和差
sprintf("2+3=%d",c) %输出和
sprintf("2-3=%d",d) %输出差
function [c,d]=mycomp0(a,b) %计算两个给定值的和和差
c=a+b;
d=a-b;
end
运行脚本,在命令窗口输出以下结果。
>> mycomp
ans=
"2+3=5"
ans=
"2-3=-1"
【Python】
函数有多个返回值时可以用return语句直接返回,也可以将各返回值写入列表,然后返回列表。
下面定义1个函数,指定2个参数值,返回它们的和和差。该文件路径为Samples\ch10\Python\sam14-003.py。
def mycomp(a,b): #计算两个给定值的和和差
c=a+b
d=a-b
return c,d
c,d=mycomp(2,3) #调用mycomp函数,计算2和3的和和差
print('2+3={}'.format(c)) #输出和
print('2-3={}'.format(d)) #输出差
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,则IDLE命令行窗口显示下面的结果:
>>> =RESTART: …/Samples/ch14/sam14-003.py
2+3=5
2-3=-1
有多个返回值时,也可以将这多个返回值添加到列表中,用return语句返回该列表。下面改写上例。该文件路径为Samples\ch14\sam14-004.py。
def mycomp(a,b): #计算两个给定值的和和差
data=[]
data.append(a+b)
data.append(a-b)
return data #和和差以列表返回
data=mycomp(2,3) #调用mycomp函数,计算2和3的和和差
print(data) #输出元素为和和差的列表
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,则IDLE命令行窗口显示下面的结果:
>>> =RESTART: …/Samples/ch14/sam14-004.py
[5, -1]
MATLAB中的主函数和子函数
任何M文件中的第1个函数都被称为主函数。主函数后面可以有任意多个子函数。
在大多数情况下,主函数是M文件中可以从MATLAB命令行或从另一个M文件函数中调用的唯一函数。在调用该函数时,使用定义该函数的M文件的名称。
打开M文件编辑器并输入一个average函数:
function y=average(x)
% 计算向量元素的平均值
y=sum(x)/length(x);
保存为M文件average.m。在MATLAB命令窗口用下面的语句计算3个数的平均值。
>> average([12 60 42])
ans =
38
注意:一般要使主函数名与M文件名相同。如果主函数名与文件名不同,则必须用文件名调用主函数。
M文件中可以包含一个以上的函数。在M文件中,除主函数外的其他函数被称为子函数,并且它们只对主函数或同一个文件中的其他子函数可见。
将主函数放在最上面,子函数放在下面,各子函数位置不分先后。
下面编写子函数mean和median用来计算输入数据的均值和中值。主函数newstats确定参数列表的长度并调用子函数,并将列表长度n传递给它们。
function [avg, med]=newstats(u) % 主函数
% 本函数用内部函数计算均值和中值
n=length(u);
avg=mean(u, n);
med=median(u, n);
function a=mean(v, n) % 子函数
% 计算均值
a=sum(v)/n;
function m=median(v, n) % 子函数
% 计算中值
w=sort(v);
if rem(n, 2) == 1
m=w((n+1) / 2);
else
m=(w(n/2) + w(n/2+1)) / 2;
end
保存为M文件newstats.m。在MATLAB命令窗口用下面的语句计算给定数据的均值和中值。
>> [avg,med]=newstats([1 2 3 4 5 6 7 8 9])
avg =
5
med =
5
即使在同一个M文件中,子函数也不能获取用于主函数或其他子函数的参数,除非将它们声明为全局变量,或者作为参数传递。
从M文件内部调用函数时,MATLAB首先检查文件,看函数是否为子函数。然后检查该名称的私有函数,最后搜索路径上的独立M文件或内部函数。
可选参数和默认参数
可选参数是非必需参数,可以有,也可以没有。默认参数是定义了默认值的参数,它们必须是可选参数,不能给必需参数定义默认值。对于可选参数而言,调用函数时如果没有赋值,就使用预先定义的默认值,如果赋了新值,就覆盖默认值。
【MATLAB】
利用nargin可以确定函数输入参数的个数。然后可以根据参数个数用条件语句完成不同的任务。在MATLAB中新建脚本文件testarg.m,文件代码为:
a=testarg1(3) %1个输入参数
b=testarg1(3,10) %2个输入参数
function c=testarg1(a, b)
if(nargin==1)
b=5; %只有1个输入参数时,b的默认值为5
c=a+b;
elseif(nargin==2)
c=a + b;
end
end
运行脚本,在命令窗口输出以下结果。
>> testargs
a =
8
b =
13
【Python】
定义函数时,对函数参数使用赋值语句可以指定该参数的默认值。下面定义para函数,该函数有两个参数,即a和b,指定b参数的默认值为5。
def para(a,b=5): #指定b参数的默认值为5
return a+b
print(para(3))
print(para(3,10))
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,则IDLE命令行窗口显示下面的结果:
>>> =RESTART: …/Samples/ch14/para.py
8
13
可见,没有传入b参数的值时,取了默认值5。
可变参数
所谓可变参数,指的是参数的个数是不确定的,可以是0个、1个直至任意个。
【MATLAB】
使用varargin可以传递任意个数的输入参数给函数。
function [out1,out2]=example(a,b,varargin)
使用元胞数组索引来提取数据。例如
y(n)=varargin{n}(2);
其中,索引表达式{n}获取varargin的第n个单元。表达式(2)表示元胞内容的第二个元素。
当允许有任意多个输出参数时,必须将所有输出打包到varargout元胞数组中。
function [i,j,varargout]=example2(x1,y1,x2,y2,flag)
利用nargout可以确定函数输出参数的个数。
varargin或varargout必须出现在参数列表的最后,即函数调用必须首先指定必要的参数。
在MATLAB中新建脚本文件mysum2.m,文件代码为:
a=mysum(1,2)
b=mysum(1,2,3,4,5)
c=mysum(1,2,3,4,5,6,7,8,9,10)
function c=mysum(a,b,varargin)
c=a+b;
for i=1:nargin-2
c=c+varargin{i}(1); %元胞数组的第1个元素
end
end
运行脚本,在命令窗口输出以下结果。
>> mysum2
a =
3
b =
15
c =
55
【Python】
Python中包含可变参数的函数的定义如下所示:
def functionname([args,] *args_tuple ):
函数体
return [表达式]
其中,[args,]定义必选参数,*args_tuple定义可变参数。*args_tuple是作为1个元组传递进来的。
下面定义1个函数进行求和运算,该运算的第1个数据是确定的,后面的数据不确定,数据个数和数据大小都不确定。该文件路径为Samples\ch10\Python\sam14-006.py。
def mysum(arg1,arg2,*vartuple): # arg1,arg2为必选参数,*vartuple为可变参数
sum=arg1+arg2
for var in vartuple: #累加求和
sum+=var
return sum
a=mysum(1,2) #调用mysum函数,指定参数求和
b=mysum(1,2,3,4,5)
c=mysum(1,2,3,4,5,6,7,8,9,10)
print(a)
print(b)
print(c)
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,则IDLE命令行窗口显示下面的结果:
>>> =RESTART: …/Samples/ch14/mysum.py
3
15
55
传值还是传址
在函数中,对象作为参数传递时,需要搞清楚函数传递的是对象的地址还是对象的值。传址和传值的主要区别在于,如果在函数体中对参数的值进行了修改,调用该函数前后,如果是传址方式传递,该参数的值会改变,如果是传值方式传递,该参数的值不变。
【MATLAB】
在MATLAB中新建脚本文件TP.m,文件代码为:
b="hello"; %给变量b赋初值"hello"
TP0(b); %将变量b作为参数调用函数
b %输出变量b的值
function TP0(a)
a="MATLAB"; %修改参数的值为"MATLAB"
end
运行脚本,在命令窗口输出以下结果。
>> TP
b=
"hello"
可见,调用函数前后变量的值不变,MATLAB中参数按照传值方式传递。
【Python】
在Python中,对于不可变类型,包括字符串、元组和数字,作为函数参数时是按传值方式传递的。此时传递的是对象的值,修改的是一个复制的对象,不影响对象本身。对于可变类型,包括列表和字典,作为函数参数时是按传址方式传递的。此时传递对象本身,修改它后在函数外部也会受影响。
下面举例进行说明。对于不可变类型,下面的函数传递1个字符串,查看调用该函数前后参数的值有没有变化。该文件路径为Samples\ch14\sam14-008.py。
def TP(a):
a='python' #修改参数的值为"python"
b='hello' #给变量b赋初值"hello"
TP(b) #将变量b作为参数调用函数
print(b) #输出变量b的值
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,则IDLE命令行窗口显示下面的结果:
>>> =RESTART: …/Samples/ch14/sam14-008.py
hello
可见,调用函数前后变量的值不变,参数按照传值方式传递。
对于可变类型,下面的函数传递1个列表,在函数体中给列表添加1个列表元素。该文件路径为Samples\ch14\sam14-009.py。
def TP(lst): #参数为列表
lst.append([6,7,8,9]) #给传入的列表添加1个列表元素
return
lst=[1,2,3,4,5]
print(lst)
TP(lst) #将列表作为参数调用函数
print(lst)
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,则IDLE命令行窗口显示下面的结果:
>>> =RESTART: …/Samples/ch14/sam14-009.py
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, [6, 7, 8, 9]]
可见,调用函数前后列表发生了变化,参数按照传址方式传递。
匿名函数
顾名思义,匿名函数就是没有显式命名的函数。它用更简洁的方式定义函数。
【MATLAB】
使用匿名函数,可以在不必创建M文件的情况下快速创建简单函数。可以在MATLAB命令行或任何M文件函数或脚本中创建匿名函数。
创建匿名函数的语法格式为:
fhandle=@(arglist) expr
其中,expr表示函数体,即函数要完成主要工作的代码;arglist为要传递给函数的逗号间隔的输入参数列表。
【Python】
Python中使用lambda关键字创建匿名函数,语法格式为:
fn=lambda [arg1 [,arg2, …, argn]]: 表达式
其中,lambda为关键字,在它后面声明参数,然后在冒号后面书写函数表达式。fn可作为函数的名称使用,调用格式为:
v=fn(arg1 [,arg2, …, argn])
下面在命令行中定义1个对2个数求积的匿名函数。
>>> rt=lambda a,b: a*b
该函数有2个参数a和b,函数表达式为a*b。
调用该函数,计算和输出给定数据的积:
>>> print(rt(2,5))
10