Python之旅——函数继续冲

情人节单身博主继续陪你Python冲冲冲(抬起头不让眼泪滑下)


函数和过程

C_T在学Pascal的时候,函数和过程是两个完全不同的东西
但是转了C++之后,所有人就好像忘记了过程这种东西,全部都用 " 函数 " 称呼了

实际上很多语言都是将函数和过程分为论之的,简单来说:
函数 ( function ) 拥有返回值
过程 ( procedure ) 是简单,特殊并且没有返回值的

但是Python从严格意义上说,只有函数,没有过程

def hello():
	print('Hello world!')

>>> temp = hello()
Hello world!
>>> temp
>>> print(temp)
None
>>> type(temp)
<class 'NoneType'>

像上面的这个栗子:
我们定义一个 " 没有返回值 " 的函数,且令temp = hello()
我们直接获取temp是没有输出显示的,但是我们如果用print访问ta,得到的是None
也就是说,这个函数在没有人工定义返回值的时候,会自动返回一个None
严格意义上来说,这也是拥有返回值的


再谈返回值

目前为止,在我们的潜意识里函数都只能有一个返回值
但是,Py可以有多个返回值
当然我这种描述方式可能会产生异议
实际上,Py函数可以将多个返回值打包成一个列表或元组,直观上认为拥有了多个返回值

def test():
	return [1,2,3.14,'ABC']
>>> test()
[1, 2, 3.14, 'ABC']

def test():
    return 1,2,3.14,'ABC'
>>> test()
(1, 2, 3.14, 'ABC')

局部变量和全局变量

我私以为在Py中只要不是在函数中定义的变量都是全局变量
众所周知,我们不能在主程序中访问局部变量

def cal_balance(balance,rate):
    now = balance * (1 + rate)
    return now

balance = float(input('Please input the balance: '))
rate = float(input('Please input the yearly rate: '))
print('After a year, the balance is',cal_balance(balance,rate))

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # 

Please input the balance: 100
Please input the yearly rate: 0.03
After a year, the balance is 103.0

但是我们可以在函数中访问全局变量

def cal_balance(balance,rate):
    print('The balance is',balance)
    # 访问全局变量
    now = balance * (1 + rate)
    return now

balance = float(input('Please input the balance: '))
rate = float(input('Please input the yearly rate: '))
print('After a year, the balance is',cal_balance(balance,rate))

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # 

Please input the balance: 100
Please input the yearly rate: 0.03
The balance is 100.0
After a year, the balance is 103.0

不过我们在下面这个栗子中,试图在函数中更改全局变量
这个时候我们就会发现,出事了——
我们明明在函数中更改了全局变量balance,但为什么主程序中的balance,却没有发生改变呢?
实际上,当我们在函数中试图更改全局变量的时候
函数会自动生成一个与全局变量同名的局部变量(存储在栈中),这两者是互不影响的
专业一点的说法:Python会使用屏蔽(shadowing)的方式保护全局变量

所以尽量不要在函数中修改全局变量
def cal_balance(balance,rate):
    # print('The balance is',balance)
    balance = 99
    print('The balance(*) is',balance)
    now = balance * (1 + rate)
    return now

balance = float(input('Please input the balance: '))
rate = float(input('Please input the yearly rate: '))
print('After a year, the balance is',cal_balance(balance,rate))
print('The balance is',balance)

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # 

Please input the balance: 100
Please input the yearly rate: 0.03
The balance(*) is 99
After a year, the balance is 101.97
The balance is 100.0

global关键字

好吧,你说你真的想要在函数中更改全局变量?
那我就再教你一招:
我们只需要在变量前面添加global关键字即可:

global balance = 99

内嵌函数

顾名思义,就是在函数内部再继续定义函数
感觉有点蠢蠢的亚子。。。

def func1():
    print('func1调用中...')
    def func2():
        print('func2调用中...')
    func2()

>>> func1()
func1调用中...
func2调用中...

有什么用处呢?
目前还没看出来。。。我们可以把内嵌函数视为下面要介绍的闭包的知识铺垫
有什么特殊性质呢?
非常合理得,我们不能从函数外部调用内嵌函数

def func1():
    print('func1调用中...')
    def func2():
        print('func2调用中...')
    func2()

>>> func1()
func1调用中...
func2调用中...
>>> func2()
Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    func2()
NameError: name 'func2' is not defined

闭包

(在这篇文章中,我对于闭包只进行一个最浅层的引入,详细介绍请移步文末寻找链接)

闭包是函数式编程的一个重要的语法结构
函数式编程是一种编程方式,ta对代码进行高度的概括和精炼,从而提高代码的重用性
著名的函数式编程语言之一就是LISP,主要用于绘图和人工智能

不同的编程语言实现闭包的方式不同,Py中的闭包从表现形式上定义为:

如果在一个内部函数里,对外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就会被认为是闭包(closure)

举个栗子:

def FunX(x):
    def FunY(y):
	    return x * y
    return FunY
    # 注意到了吗,返回函数没有括号

>>> i = FunX(8)
>>> i
<function FunX.<locals>.FunY at 0x03D16EC8>
>>> type(i)
<class 'function'>
>>> i(5)
40
>>> FunX(8)(5)
40

在这个栗子中,
FunY作为内层函数,调用了FunX(外层非全局域)的参数x,符合闭包的特点,所以我们称FunY为闭包

调用时,我们可以把FunX(x)直接赋值给变量,
这个变量实际上就变成了内部函数(闭包)的别名,之后再通过这个函数式变量进行调用
当然我们也可以通过两个括号调用函数,第一个括号内填写外部作用域的参数,第二个括号内填写闭包的参数
需要注意的是,我们不能在外部直接调用闭包

鉴于闭包是一个非常重要的内容,而且这里的介绍简直是胡言乱语,云里雾里,所以我打算专门写一篇文章介绍闭包
请各位移步。。。
发布了951 篇原创文章 · 获赞 205 · 访问量 33万+

猜你喜欢

转载自blog.csdn.net/wu_tongtong/article/details/104294953