第七章 函数

7.1 定义函数

def greeting(username):
   print("Hello, " + username + "!")


greeting('Tom') # 调用函数

输出:Hello, Tom!

7.2 传递实参

向函数传递实参的方式很多,可使用 位置实参 ,这要求实参的顺序和形参的顺序相同;也可以使用 关键字实参 ,其中每个参数都由变量名和值组成;还可以使用列表和字典。

7.2.1 位置实参

你调用函数时,Python必须将函数调用的每个实参都关联到函数定义中的一个形参。为此,最简单的关联方式是基于实参的顺序。这种方式被称为 位置实参
def best_book(book_name, book_type):
    print("The best book is " + book_name)
    print("It's a " + book_type)

best_book("Lucy", "scientific")

输出:

The best book is Lucy
It's a scientific

调用方式与C大体相同,不多赘述。

7.2.2 关键字实参

关键字实参 是传递给函数的 名称-值对。你直接在实参总将名称和值关联起来,因此向函数传递参数时不会混淆顺序。关键字实参让你无需考虑函数调用中的实参顺序,还清除指出各个值的用途。
def best_book(book_name, book_type):
    print("The best book is " + book_name)
    print("It's a " + book_type)

best_book(book_type = "scientific", book_name = 'Lucy')

输出同上

7.2.3 默认值

编写函数时,可以给每个形参指定默认值。

def best_book(book_name, book_type='scientific'):
    print("The best book is " + book_name)
    print("It's a " + book_type)


best_book(book_name='Lucy')
def best_book(book_name, book_type='scientific'):
    print("The best book is " + book_name)
    print("It's a " + book_type)


best_book('Lucy')

输出皆为同上

  • 有默认值的形参必须放在无默认值的形参后面(与C++相同)

7.3 返回值

def name(first_name, last_name):
    full_name = first_name + " " + last_name
    return full_name.title()

me = name('Eion', 'Lee')
print(me)

Eion Lee

7.3.1 让实参变成可选的

就上面的例子来说,考虑到有的人有中间名,有的人没有

def name(first_name, last_name, middle_name = ''):
    if middle_name:
        full_name = first_name + " " + middle_name + " " + last_name
    else:
        full_name = first_name + " " + last_name
    return full_name.title()


me = name('Eion', 'Lee')
you = name('TZ', 'BEX', 'F')
print(me)
print(you)

Eion Lee

Tz F Bex

7.3.2 返回字典

返回值可以是复杂的变量,比如字典和列表。

def person(fn, ln, gd):
    p = {
        'first_name': fn,
        'last_name': ln,
        'gender': gd
    }
    return p


T1 = person('Eion', 'Lee', 'male')
print(T1)

{'first_name': 'Eion', 'last_name': 'Lee', 'gender': 'male'}

def person(f, s, t):
    p = [f, s, t]
    return p


T1 = person(1, 2, 3)
print(T1)

[1, 2, 3]

7.4 传递列表

将列表传递给函数非常有用。函数可以直接访问列表的内容,并对其进行修改。

def greeting(names):
    for name in names:
        print("Hello, " + name + "!")

guests = ['Tom','Alice','Bob']
greeting(guests)

Hello, Tom!

Hello, Alice!
Hello, Bob!

7.4.1 用函数修改列表

def print_list(required):
    finished = []
    while required:
       cur = required.pop()
       print(cur + " finished")
       finished.append(cur)
    return finished


re = ['Tom', 'Alice', 'Bob']
fi = print_list(re)
print("\nUninished:")
print(re)

Bob finished

Alice finished
Tom finished

Uninished:

[]

7.4.2 禁止函数修改列表

有时不需要函数修改列表。比如打印完后,还想查阅原来需要打印的名单,则不能让函数修改这份名单。
为解决这个问题,可以向函数传递列表的副本,而不是原列表
传递列表的副本可以这样做:

print_list(re[:])
即: 将列表的完整切片传递给函数。
def print_list(required):
    finished = []
    while required:
       cur = required.pop()
       print(cur + " finished")
       finished.append(cur)
    return finished


re = ['Tom', 'Alice', 'Bob']
fi = print_list(re[:])
print("\nRequired:")
print(re)

Bob finished

Alice finished
Tom finished

Required:
['Tom', 'Alice', 'Bob']

7.5 传递任意数量的参数

有时候,预先不知道要传递多少个实参。但Python允许函数从调用语句中收集任意数量的实参。

例如,要计算若干个正数的和。下面的函数只有一个形参*nums,不管调用语句提供多少实参,这个形参都会把它们收入到一个元组中。

def summ(*nums):
    sum = 0
    for i in nums:
        sum += i
    return sum

s = summ(1,2,3,4,5,6,7)
print(s)

28

形参名*nums中的星号让Python创建一个名为nums的空元组,并将所有收到的参数都封装进去。

def summ(*nums):
    sum = 0
    print(nums)
    for i in nums:
        sum += i
    return sum

s = summ(1,2,3,4,5,6,7)

(1, 2, 3, 4, 5, 6, 7)

7.5.1 结合使用位置参数和任意数量实参

如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量的实参的形参放在最后。
def pizza(size, *ingds):
    print("Size: " + str(size))
    for ingd in ingds:
        print(" - " + ingd)

pizza(12, 'pepper', 'tomato')
pizza(14, 'potato')

Size: 12
- pepper
- tomato
Size: 14
- potato

7.5.2 使用任意数量的关键字实参

有时候,需要接受任意数量的实参,但预先不知道传递给函数的是什么样的信息。在这种情况下,可将函数编写成能够接受任意数量的键-值对。
比如要生成一份简历,但不知道会加入多少信息。

def profile(name, gender, **info):
    p = {'name': name, 'gender': gender}
    for key, value in info.items():
        p[key] = value
    return p

me = profile('Eion', 'male', age='18', job='stu')
print(me)

{'name': 'Eion', 'gender': 'male', 'age': '18', 'job': 'stu'}

形参名**info中的两个星号让Python创建一个名为info的空字典,并将所有收到的键值对都封装进去。

7.6 将函数存储在模块中

函数的有点之一是,使用它们可以将代码块与主程序分离。通过给函数指定描述性名称,可让主程序容易理解的多。你还可以更进一步,将函数存储在被称为<font face = "楷体">模块</font>的独立文件中,在将模块<font face = "楷体">导入</font>到主程序。
import语句允许当前运行的程序文件中使用模块的代码。

7.6.1 导入整个模块

# func.py
def profile(name, gender, **info):
    p = {'name': name, 'gender': gender}
    for key, value in info.items():
        p[key] = value
    return p

# main.py
import func

me = func.profile('Eion', 'male', age='18', job='stu')
print(me)

{'name': 'Eion', 'gender': 'male', 'age': '18', 'job': 'stu'}

7.6.2 导入特定的函数

还可以导入模块中的特定函数,语法如下:
from 模块名 import 函数1, 函数2, ....
通过逗号分隔多个函数

  • 若用这种语法,则调用函数时不需要用句点指定模块名。
# func.py
def profile(name, gender, **info):
    p = {'name': name, 'gender': gender}
    for key, value in info.items():
        p[key] = value
    return p

# main.py
from func import profile

me = profile('Eion', 'male', age='18', job='stu')
print(me)

7.6.3 使用as给函数/模块指定别名

from func import profile as pf
import func as fc

7.6.4 导入模块中的所有函数

from func import *

该语句中的星号让Python将模块func中的所有函数复制到这个程序文件中。

  • 由于是导入函数,所以所有函数都不需要加句点调用。
  • 但最好不要采用这种方法:如果遇到不同模块中有着相同名称的函数,则会出错。