定义一个函数

函数用关键字 def 来定义。def 关键字后跟一个函数的标识符名称,然后跟一对圆括号。圆括号之中可以包括一些变量名,该行以冒号结尾。接下来是一块语句,它们是函数体。

def sayHello():
    print('Hello World!')
#调用
sayHello()

函数的参数

参数在函数定义的圆括号对内指定,用逗号分割。

def printMax(a,b):
    if a > b:
        print(a)
    else:
        print(b)

局部变量

当你在函数定义内声明变量的时候,它们与函数外具有相同名称的其他变量没有任何关系,即变量名称对于函数来说是局部的。这称为变量的作用域。所有变量的作用域是它们被定义的块,从它们的名称被定义的那点开始。

x = 50

def func(x):
    print('x is', x)
    x = 2
    print('Changed local x to', x)

func(x)
print('x is still', x)

使用全局语句

如果你想要为一个定义在函数外的变量赋值,那么你就得告诉 Python 这个变量名不是局部的,而是全局的。我们使用 global 语句完成这一功能。

你可以使用定义在函数外的变量的值(假设在函数内没有同名的变量)。然而,我并不鼓励你这样做,并且你应该尽量避免这样做,因为这使得程序的读者会不清楚这个变量是在哪里定义的。使用 global 语句可以清楚地表明变量是在外面的块定义的。

x = 50

def func(x):
    global x
    print('x is', x)
    x = 2
    print('Changed local x to', x)

func(x)
print('x is still', x)

使用非局部语句

上面给出了如何在局部和全局作用域内使用变量。还有一种作用域叫做 “非局部” 域,处于这两种作用域之间。
非局部作用域在你定义函数内的函数时会看到。

由于在 Python 中,任何事物是可执行的代码,你可以在任何地方定义函数。

def func_outer():
    x = 2
    print('x is',x)

    def func_inner():
        nonlocal x
        x = 5

     func_inner()
     print('Changed local x to',x)

func_outer()

默认参数值

对于一些函数,你可能希望它的一些参数是可选的,如果用户不想要为这些参数提供值的话,这些参数就使用默认值。这个功能借助于默认参数值完成。你可以在函数定义的形参名后加上赋值运算符(=)和默认值,从而给形参指定默认参数值。

def say(message, times = 1):
    print(message * times)

say('Hello')
say('World', 5)

只有在形参表末尾的那些参数可以有默认参数值,即你不能在声明函数形参的时候,先声明有默认值的形参而后声明没有默认值的形参。这是因为赋给形参的值是根据位置而赋值的。例如,def func(a, b=5) 是有效的,但是 def func (a=5, b) 是无效的。

关键参数

如果你的某个函数有许多参数,而你只想指定其中的一部分,那么你可以通过命名来为这些参数赋值—— 这被称作关键参数—— 我们使用名字(关键字)而不是位置(我们前面所一直使用的方法)来给函数指定实参。

这样做有两个优势—— 一、由于我们不必担心参数的顺序,使用函数变得更加简单了。二、假设其他参数都有默认值,我们可以只给我们想要的那些参数赋值。

def func(a, b=5, c=10):
    print('a is', a, 'and b is', b, 'and c is', c)

func(3, 7)
func(25, c=24)
func(c=50, a=100)

VarArgs 参数

有时,你或许想定义一个能获取任意个数参数的函数,这可通过使用 * 号来实现。

def total(initial=5, *numbers, **keywords):
    count = initial
    for number in numbers:
        count += number
    for key in keywords:
        count += keywords[key]
    return count

print(total(10, 1, 2, 3, vegetables=50, fruits=100))

当我们定义一个带星的参数,像 * param 时,从那一点后所有的参数被收集为一个叫做’param’ 的列表。(译者注:如在该例中,首先会给 initial 的值由 5 变成 10 ,然后 numbers 将 1,2,3,收集作为一个列表 numbers=(1,2,3))。

当我们定义一个带两个星的参数,像 **param 时,从那一点开始的所有的关键字参数会被收集为一个叫做’param’ 的字典。(译者注:在该例子中,从 vegetables=50 后的所有参数收集为一个字典 keywords=’vegetables’: 50, ’fruits’:100)。

Keyword-only 参数

如果想指定特定的关键参数为 keywor-only 而不是位置参数,可以在带星的参数后声明

def total(initial=5, *numbers, vegetables):
    count = initial
    for number in numbers:
        count += number
    count += vegetables
    return count

print(total(10, 1, 2, 3, vegetables=50))
print(total(10, 1, 2, 3,))
# Raises error because we have not supplied a default argument value for 'vegetables'

在带星号的参数后面申明参数会导致 keyword-only 参数。如果这些参数没有默认值,且像上面那样不给关键参数赋值,调用函数的时候会引发错误。

如果你想使用 keyword-only 参数,但又不需要带星的参数,可以简单地使用不适用名字的空星,如 def total(initial=5, *, vegetables)。

return 语句

return 语句用来从一个函数返回即跳出函数。也可选是否从函数返回一个值。

DocStrings

Python 有一个很奇妙的特性,称为文档字符串,它通常被简称为 docstrings 。DocStrings 是一个重要的工具,由于它帮助你的程序文档更加简单易懂,你应该尽量使用它。你甚至可以在程序运行的时候,从函数恢复文档字符串!

    def printMax(x, y):
        '''Prints the maximum of two numbers.

        The two values must be integers.'''
    x = int(x) # convert to integers, if possible
    y = int(y)

    if x > y:
        print(x, 'is maximum')
    else:
        print(y, 'is maximum')

printMax(3, 5)
print(printMax.__doc__)

模块简介

编写模块有各种各样的方法,但最简单的方法就是创建以. py 为扩展名的文件,在文件中包含函数和变量。

模块可以从另外一个程序导入来使用其函数的功能。

使用 import sys 导入模块

按字节编译的. pyc 文件

导入一个模块相对来说是一个比较费时的事情,所以 Python 做了一些技巧,以便使输入模块更加快一些。一种方法是创建按字节编译的文件,这些文件以. pyc 作为扩展名。字节编译的文件与 Python 变换程序的中间状态有关。当你在下次从别的程序输入这个模块的时候,.pyc 文件是十分有用的—— 它会快得多,因为一部分输入模块所需的处理已经完成了。另外,这些字节编译的文件也是与平台无关的。

这些. pyc 文件通常与. py 文件相同的方式在相同路径被创建。如果 Python 没有写入当前路径的权限,.pyc 文件就不会被创建。

from...import... 语句

如果你想要直接输入 argv 变量到你的程序中(避免在每次使用它时打 sys.),那么你可以使用 from sys import argv 语句。如果你想要输入所有 sys 模块使用的名字,那么你可以使用 from sys import * 语句。这对于所有模块都适用。

一般说来,应该避免使用 from..import 而使用 import 语句,因为这样可以使你的程序更加易读,也可以避免名称的冲突。

模块的 name

每个模块都有一个名称,在模块中可以通过语句来找出模块的名称。这在一个场合特别有用—— 就如前面所提到的,当一个模块被第一次输入的时候,这个模块的主块将被运行。假如我们只想在程序本身被使用的时候运行主块,而在它被别的模块输入的时候不运行主块,我们该怎么做呢?这可以通过模块的 name 属性完成。

if __name__ == '__main__':
    print('This program is being run by itself')
else:
    print('I am being imported from another module')

每个 Python 模块都有它的 name,如果它是’main’,这说明这个模块被用户单独运行,我们可以进行相应的恰当操作。

创建自己的模块

创建你自己的模块是十分简单的,你一直在这样做!每个 Python 程序也是一个模块。你已经确保它具有. py 扩展名了。

def sayhi():
    print('Hi, this is mymodule speaking.')

 __version__ = '0.1'

注意如果已经在导入 mymodule 的模块中申明了一个 version 的名字,这就会有冲突。这也是有可能的,因为从实际情况来看,每个模块会用这个名字来申明它的版本。因此,推荐选择使用 import 语句,虽然会导致程序稍微有点冗长。

包是模块的文件夹,有一个特殊的__init__.py 文件,用来表明这个文件夹是特殊的因为其包含有 Python 模块。