Python函数和模块的使用

在讲解本章节的内容之前,我们先来研究一道数学题,请说出下面的方程有多少组正整数解。

在这里插入图片描述
在这个数学问题中,我们需要求解一个方程有多少组正整数解。而这个方程实际上等同于将8个苹果分成四组,每组至少一个苹果,有多少种方案。这是一个经典的组合问题,可以通过数学方法求解。当我们意识到这一点后,问题的答案就呼之欲出了,让我们一起来尝试吧!


可以用Python的程序来计算出这个值,代码如下所示。

m = int(input('m = '))
n = int(input('n = '))
fm = 1
for num in range(1, m + 1):
    fm *= num
fn = 1
for num in range(1, n + 1):
    fn *= num
fm_n = 1
for num in range(1, m - n + 1):
    fm_n *= num
print(fm // fn // fm_n)

函数的作用

这段文档中的代码中有重复的计算阶乘的代码。为了避免重复代码,我们可以将计算阶乘的功能封装到一个称之为“函数”的功能模块中,在需要计算阶乘的地方,我们只需要“调用”这个“函数”就可以了。

定义函数

在Python中可以使用def关键字来定义函数。函数名可以根据变量命名规则进行定义,圆括号中可以放置传递给函数的参数。函数执行完成后我们可以通过return关键字来返回一个值。

以下是重构后的代码:

def factorial(num):
    """计算阶乘"""
    result = 1
    for n in range(1, num + 1):
        result *= n
    return result

# 主程序
m = int(input('m = '))
n = int(input('n = '))
print(factorial(n) // factorial(m) // factorial(n - m))

这段文档中的代码展示了如何在Python中定义函数。函数的定义以def关键字开头,后跟函数名和一组圆括号。函数的主体则包含在缩进块中。在函数内部,我们可以定义任意数量的变量、执行任意数量的语句和返回任意类型的值。在文档中的例子中,我们定义了一个名为factorial的函数,用于计算阶乘。了解了函数的定义后,我们就可以将计算阶乘的代码封装成函数,避免代码重复。

函数的参数

函数是绝大多数编程语言中都支持的一个代码的"构建块",但是Python中的函数与其他语言中的函数还是有很多不太相同的地方。其中一个显著的区别是Python对函数参数的处理。Python中的函数参数可以有默认值,也支持使用可变参数。这些特性使得Python不需要像其他语言一样支持函数的重载。

在Python中,我们可以为函数的参数设置默认值,这样当函数被调用时,如果没有传入该参数的值,函数会使用默认值。这种方式可以方便地处理一些常见的情况,例如函数中有一个可选参数。

除了默认参数外,Python还支持使用可变参数。可变参数允许我们定义一个函数,它可以接收任意数量的参数。这些参数被包装为一个元组或字典,然后传递给函数。这种方式可以方便地处理一些不确定参数数量的情况。

因为Python中的函数参数处理方式的灵活性,我们在定义一个函数的时候可以让它有多种不同的使用方式。下面是两个小例子:

from random import randint


def roll_dice(n=2):
    """摇色子"""
    total = 0
    for _ in range(n):
        total += randint(1, 6)
    return total


def add(a=0, b=0, c=0):
    """三个数相加"""
    return a + b + c


# 如果没有指定参数那么使用默认值摇两颗色子
print(roll_dice())
# 摇三颗色子
print(roll_dice(3))
print(add())
print(add(1))
print(add(1, 2))
print(add(1, 2, 3))
# 传递参数时可以不按照设定的顺序进行传递
print(add(c=50, a=100, b=200))

我们在这段文本中定义了两个函数,一个带默认参数,一个带可变参数。这些特性使得Python中的函数与其他语言中的函数还是有很多不太相同的地方。Python中的函数参数可以有默认值,也支持使用可变参数。这些特性使得Python不需要像其他语言一样支持函数的重载。因此,在Python中我们可以让一个函数有多种不同的使用方式。

def add(*args):
    """
    This function can take any number of arguments and returns their sum.
    """
    result = 0
    for arg in args:
        result += arg
    return result

上面的add函数使用了可变参数,这样就可以接受任意数量的参数来进行加法运算。因为我们可能会对0个或多个参数进行加法运算,而具体有多少个参数是由调用者来决定,我们作为函数的设计者对这一点是一无所知的,因此在不确定参数个数的时候,我们可以使用可变参数。

用模块管理函数

对于任何一种编程语言来说,给变量、函数这样的标识符起名字都是一个让人头疼的问题,因为我们会遇到命名冲突这种尴尬的情况。最简单的场景就是在同一个.py文件中定义了两个同名函数,由于Python没有函数重载的概念,那么后面的定义会覆盖之前的定义,也就意味着两个函数同名函数实际上只有一个是存在的。

def foo():
    print('hello, world!')


def foo():
    print('goodbye, world!')


# 下面的代码会输出什么呢?
foo()

当然上面的这种情况我们很容易就能避免,但是如果项目是由多人协作进行团队开发的时候,团队中可能有多个程序员都定义了名为foo的函数,那么怎么解决这种命名冲突呢?答案其实很简单,Python中每个文件就代表了一个模块(module),我们在不同的模块中可以有同名的函数,在使用函数的时候我们通过import关键字导入指定的模块就可以区分到底要使用的是哪个模块中的foo函数,代码如下所示。

module1.py

def foo():
    print('hello, world!')

module2.py

def foo():
    print('goodbye, world!')

test.py

from module1 import foo

# 输出hello, world!
foo()

from module2 import foo

# 输出goodbye, world!
foo()

也可以按照如下所示的方式来区分到底要使用哪一个foo函数。

test.py

import module1 as m1
import module2 as m2

m1.foo()
m2.foo()

但是如果将代码写成了下面的样子,那么程序中调用的是最后导入的那个foo,因为后导入的foo覆盖了之前导入的foo

test.py

from module1 import foo
from module2 import foo

# 输出goodbye, world!
foo()

test.py

from module2 import foo
from module1 import foo

# 输出hello, world!
foo()

需要说明的是,如果我们导入的模块除了定义函数之外还中有可以执行代码,那么Python解释器在导入这个模块时就会执行这些代码,事实上我们可能并不希望如此,因此如果我们在模块中编写了执行代码,最好是将这些执行代码放入如下所示的条件中,这样的话除非直接运行该模块,if条件下的这些代码是不会执行的,因为只有直接执行的模块的名字才是"__main__"。

module3.py

def foo():
    pass


def bar():
    pass


# __name__是Python中一个隐含的变量它代表了模块的名字
# 只有被Python解释器直接执行的模块的名字才是__main__
if __name__ == '__main__':
    print('call foo()')
    foo()
    print('call bar()')
    bar()

test.py

import module3

# 导入module3时 不会执行模块中if条件成立时的代码 因为模块的名字是module3而不是__main__

练习

练习1:实现计算求最大公约数和最小公倍数的函数。
练习2:实现判断一个数是不是回文数的函数。
练习3:实现判断一个数是不是素数的函数。
练习4:写一个程序判断输入的正整数是不是回文素数。

免费下载答案源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联小助手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值