05 函数和命名空间 | Python入门教程

函数

函数是实现一定功能的代码段,传入参数,返回值。

Python 内置函数len,给它传入一个列表,它会返回列表的长度(返回值);print函数把传入的对象打印到屏幕上,它没有返回任何值,我们说它返回Noneinput函数的返回值是屏幕输入的字符串。

函数定义

def关键字定义函数,参数写在函数名后的括号内,返回值写在return后。为了便于理解,下面的例子将自定义一个二次函数f,传入参数是自变量x,函数返回计算出的因变量的值

def f(x):  # 函数定义
    y = x * x
    return y

a = int(input('输入一个整数:'))
b = f(a)  # 函数调用
print(a, '的平方是', b)

运行结果

输入一个整数:4
4 的平方是 16

函数的使用能提高应用的模块性,和代码的重复利用率。

传入参数

必须参数

参数可以有0个,1个或多个,写在变量名后的括号内。定义函数时指定了多少参数,调用时就要传入多少参数。

下面的例子中,定义一个打印三角形的函数和一个打印一行字符串的函数

def print_line(t, symbol):
    print(symbol * t)

def print_triangle(t, symbol):
    for x in range(1, t + 1):
        print_line(x, symbol)

print_triangle(5, 'O')

运行结果

O
OO
OOO
OOOO
OOOOO

默认参数

如果定义函数时设置了默认参数,则在函数调用时可以不传入对应参数,函数会使用默认参数。下面的例子设置了symbol的默认值为5,因此在函数调用时可以不传入该参数

def print_line(t, symbol='#'):
    print(symbol * t)

def print_triangle(t, symbol='#'):
    for x in range(1, t + 1):
        print_line(x, symbol)

print_triangle(4)  # 函数使用默认参数 symbol='#'
print() # 空行
print_triangle(5, 'O')

运行结果

#
##
###
####

O
OO
OOO
OOOO
OOOOO

默认参数都要写在必须参数的后面,不能写成def print_line(symbol='#', t):

返回值

return后的对象叫做返回值。实际编程中,对于返回值非空的函数,常常用一个变量接收返回值。遇到return时,函数返回返回值,同时会立即退出函数。下面的str_date函数,把传入的年月日组合成一个时间字符串,然后返回这个时间字符串。

def str_date(year, month, day):
    date = str(year) + '-' + str(month) + '-' + str(day)
    if day == 1:
        date += 'st'
        return date
    elif day == 2:
        date += 'nd'
        return date
    elif day == 3:
        date += 'rd'
        return date
    date += 'th'  # 当day<=3时,函数不会执行到这里
    return date

d1 = str_date(2006, 6, 6)
d2 = str_date(2003, 8, 1)

print(d1, d2)

运行结果

2006-6-6th 2003-8-1st

函数体中没有return语句的函数,默认返回空值None。前面的print_triangle就是一个返回空值的函数。

函数调用

function_name(...)的形式来调用函数,非None的返回值常用一个变量接收,如b = f(4)

关键字参数

以关键字参数的形式传入参数时,参数传入的顺序可以与定义函数时的顺序不一致,因为 Python 解释器可以用参数名匹配参数值

def str_date(year, month, day):
    date = str(year) + '-' + str(month) + '-' + str(day)
    if day == 1:
        date += 'st'
        return date
    elif day == 2:
        date += 'nd'
        return date
    elif day == 3:
        date += 'rd'
        return date
    date += 'th'
    return date

print(str_date(day=1, year=1949, month=10))

运行结果

1949-10-1st

命名空间

命名空间(namespace)是用字典实现的一个从名字到对象的映射。

简单来说,Python程序启动时,创建了一个全局命名空间。全局命名空间的键值对对应了全局变量和它储存的值(函数名和函数对象 … )。当新定义了一个全局变量时,全局命名空间就会增加一个变量名到变量的值的键值对。当修改变量的值时,全局命名空间中也会修改相应的键值对。globals函数返回全局命名空间(一个字典)

>>> a = 1
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>,
'__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>,
'a': 1}

这个字典的键'a'对应值1,也就是定义的a = 1。全局命名空间中还有一些本来就有的键值对,这对应着本来就有的全局变量和它储存的值(对象)。

>>> print(__name__)
__main__

函数调用时,会建立一个局部命名空间。在函数内定义的变量,就是这个函数的局部变量。locals函数返回当前的局部命名空间。

下面的例子定义一个change函数,尝试在函数内修改全局变量的值,并观察局部命名空间和全局命名空间

>>> def change():
...     a = 2
...     print('Local namespace:', locals())
...     print('Global namespace:', globals())
...     print(a)
... 
>>> change()
Local namespace: {'a': 2}
Global namespace: {'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None,
'__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>,
'a': 1, 'change': <function change at 0x7f8c5c39cd30>}
2
>>> a
1

change函数没有成功修改全局变量的值,这是因为Python解释器认为a = 2是在定义局部变量,因此局部命名空间增加了键值对'a': 2,但全局命名空间的键值对'a': 1没有改变。当访问一个变量时,Python首先在局部命名空间查找,然后在全局命名空间查找,最后在内置命名空间(内置的函数,变量 … )查找。这解释了为什么函数内的print(a)打印2

在函数内修改全局变量可以使用global语句,global语句可以把指定的变量绑定到全局命名空间

>>> def change():
...     global a
...     a = 2
...     print('Local namespace:', locals())
...     print('Global namespace:', globals())
... 
>>> change()
Local namespace: {}
Global namespace: {'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None,
'__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>,
'a': 2, 'change': <function change at 0x7f8c5c39cca0>}
>>> a
2

除了使用global语句,还可以直接修改全局命名空间(字典),来修改全局变量的值

>>> a = 1
>>> def change():
...     globals()['a'] = 2  # 直接修改
...     print('Local namespace:', locals())
...     print('Global namespace:', globals())
... 
>>> change()
Local namespace: {}
Global namespace: {'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None,
'__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>,
'a': 2, 'change': <function change at 0x7f8c5c39cd30>}
>>> a
2

同理,也可以以locals()['name']的形式修改(创建)局部变量的值。

上一篇:自己实现word2vec


下一篇:pytorch的size和shape用法