扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
python中的函数可以返回值,也可不返回值,如果不返回值,则默认会返回None
成都创新互联公司专注于新和网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供新和营销型网站建设,新和网站制作、新和网页设计、新和网站官网定制、重庆小程序开发服务,打造新和网络公司原创品牌,更为您提供新和网站排名全网营销落地服务。
这是装饰器的简单用法。
第10行的作用就是相当于插入了一条语句:
hello=simple_ decorator(hello)
那现在的hello就是调用simple_ decorator函数并传递第10行下面的hello函数作为参数的返回值,即现在的hello成了simple_ decorator函数中定义的wrapper了,而真正的hello成了wrapper可以访问的外部函数simple_ decorator的参数f。
所以,调用hello就是调用的wrapper,而wrapper函数中对f()的访问是访问的原来的hello函数。
所以输出就是那样了。
在前面已经多次提到函数这个概念,之所以没有解释什么是函数,是因为程序中的函数和数学中的函数差不多,如input()、range()等都是函数,这些都是Python的标准函数,直接使用就可以了。根据需要,用户也可以自定义函数。
12.1 函数
函数的结构:
def 函数名(参数):
函数体
return 返回值
例如:数学中的函数f(x)=2x+5在Python中可以定义如下:
def f(x):
y=2*x+5
return(y)
如果x取值为3,可以使用如下语句调用函数:
f(3)
下面给出完整的程序代码:
def f(x):
y=2*x+5
return(y)
res=f(3)
print(res)
运行结果:11
如上例中的x是函数f(x)的参数,有时也被称为形式参数(简称形参),在函数被调用时,x被具体的值3替换y就是函数的返回值,这个值3也被称为实际参数(简称实参)。
上例中的y是函数f(x)的返回值。并不是所有的函数都有参数和返回值。如下面的函数:
def func():
print('此为无参数传递、无返回值的函数')
func()
输出结果:此为无参数传递、无返回值的函数
可以看出,该函数func()无参数,故调用时不用赋给参数值。
函数也可以有多个参数,如f(x,y)=x²+y²,可用Python语言定义如下:
def f(x,y):
z=x**2+y**2
return z
print(f(2,3)) #调用函数f(x,y)
输出结果:13
也可以通过直接给参数列表中的参数赋值的方法,为参数添加默认值,如果用户赋予参数值,则按照用户赋值执行,否则使用默认值。例如:
def f(x,y=3):
z=x**2+y**2
return z
若调用时参数列表为(2,1),即x赋值为2,y赋值为1:
print(f(2,1))
输出结果为:5
若调用时参数列表为(2),即x赋值为2,y赋值省缺,则y使用默认值:
print(f(2))
输出结果为:13
回调函数,又称函数回调,是将函数作为另一函数的参数。
例如:
def func(fun,m,n):
fun(m,n)
def f_add(m,n):
print('m+n=',m+n)
def f_mult(m,n):
print('m*n=',m*n)
func(f_add,2,3)
func(f_mult,2,3)
输出结果:
m+n= 5
m*n= 6
在f_add(m,n)和f_mult(m,n)被定义前,func(fun,m,n)中的fun(m,n)就已经调用了这两个函数,即“先调用后定义”,这也是回调函数的特点。
如果无法预知参数的个数,可以在参数前面加上*号,这种参数实际上对应元组类型。譬如,参会的人数事先不能确定,只能根据与会人员名单输入:
def func(*names):
print('今天与会人员有:')
for name in names:
print(name)
func('张小兵','陈晓梅','李大海','王长江')
运行后,输出结果为:
今天与会人员有:
张小兵
陈晓梅
李大海
王长江
参数为字典类型,需要在参数前面加上**号。
def func(**kwargs):
for i in kwargs:
print(i,kwargs[i])
func(a='a1',b='b1',c='c1')
输出结果为:
a a1
b b1
c c1
一个有趣的实例:
def func(x,y,z,*args,**kwargs):
print(x,y,z)
print(args)
print(kwargs)
func('a','b','c','Python','is easy',py='python',j='java',ph='php')
输出结果:
a b c # 前三个实参赋给前三个形参
('Python', 'is easy') # *args接收元组数据
{'py': 'python', 'j': 'java', 'ph': 'php'} # **kwargs接收字典数据
12.2 变量的作用域
变量的作用域即变量的有效范围,可分为全局变量和局部变量。
局部变量
在函数中定义的变量就是局部变量,局部变量的作用域仅限于函数内部使用。
全局变量
在主程序中定义的变量就是全局变量,但在函数中用关键字global修饰的变量也可以当做全局变量来使用。
全局变量的作用域是整个程序,也就是说,全局变量可以在整个程序中可以访问。
下面通过实例去讨论:
程序1:
a=1 # a为全局变量
def a_add():
print('a的初值:',a) # 在函数中读取a的值
a_add() # 调用函数a_add()
a+=1 # 主程序语句,a增加1
print('a现在的值是:',a) # 主程序语句,读取a的值
运行结果:
a的初值: 1
a现在的值是: 2
这个结果和我们想象的一样,全局变量a既可以在主程序中读取,也可以在子程序(函数)中读取。
程序2:
a=1
def a_add():
a+=1
print('a的初值:',a)
a_add()
print('a现在的值是:',a)
运行程序1时出现如下错误提示:
UnboundLocalError: local variable 'a' referenced before assignment
意思是:局部变量'a'在赋值之前被引用。
从语法上来讲,该程序没有错误。首先定义了一个全局变量a并赋值为1,又定义了一个函数a_add(),函数内的语句a+=1就是出错的根源,虽然我们的初衷是想让全局变量a的值增加1,但从错误提示看,这个语句中的a并不是全局变量,而是局部变量。看来,在函数中读取全局变量的值是没有问题的(在程序1中已经得到了验证),但要在函数中改变全局变量的值是不行的(在程序2的错误提示a+=1中的a 是局部变量,而非全局变量)。
怎样解决这个问题?
程序3:
a=1
def a_add(x):
x+=1
return x
print('a的初值:',a)
a=a_add(a)
print('a现在的值是:',a)
运行结果:
a的初值: 1
a现在的值是: 2
结果的确是正确的,但在函数a_add(x)中没有调用变量a(没有出现变量a)。
程序4:
a=1
def a_add(a):
a+=1
return a
print('a的初值:',a)
a=a_add(a)
print('a现在的值是:',a)
运行结果:
a的初值: 1
a现在的值是: 2
对比程序4和程序3不难发现,其实程序4只是简单的把函数的参数x变成了a,这个a的实质和程序3中的x还是一样的。这进一步证实,函数中的a是局部变量,与主程序的全局变量a有着本质的区别。
程序5:
a=1
def a_add():
global a
a+=1
print('a的初值:',a)
a_add()
print('a现在的值是:',a)
运行结果:
a的初值: 1
a现在的值是: 2
程序5和程序2相比较,仅仅是在函数中添加了一个定义“global a”,此时的局部变量a就可以当做全局变量使用,由于它和全局变量a同名,自然也就不用区分a究竟是全局变量还是局部变量了,在主程序和该函数内都可以访问、修改变量a的值了。
虽然使用global可使变量使用起来非常方便,但也容易引起混淆,故在使用过程中还是谨慎为好。
12.3 函数的递归与嵌套
递归,就是函数调用它自身。递归必须设置停止条件,否则函数将无法终止,形成死循环。
以计算阶乘为例:
def func(n):
if n==1:
return 1
else:
return n*func(n-1) #func( )调用func( )
print(func(5))
运行结果为:120
嵌套,指在函数中调用另外的函数。这是程序中常见的一种结构,在此不再赘述。
匿名函数
Python中可以在参数前加上关键字lambda定义一个匿名函数,这样的函数一般都属于“一次性”的。
例如:
程序1:这是一个常规的函数定义和调用。
def f_add(x,y):
return x+y
print(f_add(2,3))
输出结果:5
程序2:使用lambda定义匿名函数。
f_add=lambda x,y:x+y
print(f_add(2,3))
输出结果:5
从上面的代码可以看出,使用lambda仅仅减少了一行代码。f_add=lambda x,y:x+y中的f_add不是变量名,而是函数名。程序1和程序2的print( )语句中的参数都是一样的——调用函数f_add( )。所以,匿名函数并没有太多的优点。
4.6. 定义函数
我们可以创建一个用来生成指定边界的斐波那契数列的函数:
def fib(n): # write Fibonacci series up to n
... """Print a Fibonacci series up to n."""
... a, b = 0, 1
... while a n:
... print(a, end=' ')
... a, b = b, a+b
... print()
...
# Now call the function we just defined:
... fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
关键字 def 引入了一个函数 定义。在其后必须跟有函数名和包括形式参数的圆括号。函数体语句从下一行开始,必须是缩进的。
函数体的第一行语句可以是可选的字符串文本,这个字符串是函数的文档字符串,或者称为 docstring。(更多关于 docstrings 的信息请参考 文档字符串) 有些工具通过 docstrings 自动生成在线的或可打印的文档,或者让用户通过代码交互浏览;在你的代码中包含 docstrings 是一个好的实践,让它成为习惯吧。
函数 调用 会为函数局部变量生成一个新的符号表。确切的说,所有函数中的变量赋值都是将值存储在局部符号表。变量引用首先在局部符号表中查找,然后是包含函数的局部符号表,然后是全局符号表,最后是内置名字表。因此,全局变量不能在函数中直接赋值(除非用 global 语句命名),尽管他们可以被引用。
函数引用的实际参数在函数调用时引入局部符号表,因此,实参总是 传值调用 (这里的 值 总是一个对象 引用 ,而不是该对象的值)。[1] 一个函数被另一个函数调用时,一个新的局部符号表在调用过程中被创建。
一个函数定义会在当前符号表内引入函数名。函数名指代的值(即函数体)有一个被 Python 解释器认定为 用户自定义函数 的类型。 这个值可以赋予其他的名字(即变量名),然后它也可以被当作函数使用。这可以作为通用的重命名机制:
fib
f = fib
f(100)
0 1 1 2 3 5 8 13 21 34 55 89
如果你使用过其他语言,你可能会反对说:fib 不是一个函数,而是一个方法,因为它并不返回任何值。事实上,没有 return 语句的函数确实会返回一个值,虽然是一个相当令人厌烦的值(指 None )。这个值被称为 None (这是一个内建名称)。如果 None 值是唯一被书写的值,那么在写的时候通常会被解释器忽略(即不输出任何内容)。如果你确实想看到这个值的输出内容,请使用 print() 函数:
今天遇到同样的问题,就来答一波吧
1,如果是在类中,那么就很简单了,类中的一个函数调用另一个函数,只要在那个被调用的函数前加self即可(图如下,详细可以参考笔者博客),
2,如果不是在类中,(这是笔者遇到的问题),有一个简单的方法,如下sin_f函数调用sin函数(注:a=sin()不能写到sin_f()函数下,会说a没声明就调用):
3,如果是已经存在的包,那么调用包更简单了,(同样可以参考笔者上面给的那个博客第四部分)
4,最后,更多关于python问题可以参考笔者的python教程笔记
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流