Python语法之模块和包

这一节,我将为大家介绍模块和包:
> 在开发大型软件时,随着代码写的越来越多,如果将所有的代码都放在一个文件里,势必为以后的维护带来很大的困难。正如仓颉造字一样,仓颉是黄帝的史官,用祖传结绳记事的老办法记载史实。时间一长,那些大大小小,奇形怪状的绳结都记了些什么,连他自己也没法辨认了。于是,仓颉开始想新的办法,用什么方式可以帮助大家分辨清不同的事物,在仓颉的努力下,他创造了文字,解决了这个问题。而在 Python 中,为了编写易于维护的代码,我们会将代码拆分放到不同的文件里,这样每个文件包含的代码相对就会减少。在 Python 中,一个 .py 文件称为一个模块(Module)。

模块化能够带来很多好处:
(1)简化问题求解
将所有代码放在一个文件中时,我们需要考虑的是整个问题的求解,代码实现的复杂度大大增加。将代码拆分放在多个文件中时,每个文件只需要对子问题进行求解,代码实现的复杂度大大降低。
(2)提高代码可维护性
由于解决不同子问题的代码放在了不同的文件中,代码之间的依赖性小,其中一个文件的修改对其他文件产生影响的几率大大降低。维护人员可以对其中一个文件的代码进行修改,而不必熟悉其他文件中的代码。由于每个文件专注于解决一个子问题,文件之间的并行开发成为可能。
(3)提高代码可重用性
一个模块编写完成后,可以被其他地方引用。我们在编写程序的时候,也可以引用其他模块,包括 Python 内置的模块和来自第三方的模块。这样就不需要重复造轮子。大大提高了代码的复用性和开发效率。
(4)减少代码冲突
模块提供了一个独立的命名空间,独立命名空间的好处是可以避免函数名和变量名冲突。相同名字的函数和变量可以放在不同的模块中。因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。
了解了模块是什么之后,我们一起来看下如何创建模块?
```python

```
## 1. 模块的创建
模块的创建非常简单,一个 .py 文件便是一个模块(Module)。将下面的代码保存在 utils.py 文件中,这个操作是非常简单的,只需要我们创建一个文件名为 utils 的 py 文件,然后将代码复制到 utils 的 py 文件中就完成了一个模块的创建。
```
# utils.py模块
def max_num(a, b):
    if a >= b:
        return a
    else:
        return b


def min_num(a, b):
    if a > b:
        return b
    else:
        return a
```
这样我们便创建了一个名为 utils 的模块,在这个模块中,定义了两个函数: max_num和min_num ,两个函数分别为求两个数中的大数和小数。
## 2. 模块的导入
### 2.1import <module_name>
模块创建完成后,可以使用 import 关键字来导入模块,例如:
```
import utils
```
我们看到通过 import 模块名 的方式完成了模块导入。
执行上述指令后,Python 首先会从自己内置模块中查找是否含有该模块的定义,若未查询到会从 sys.path 对应的模块路径查询是否含有对应模块的定义,如果搜索完成,仍然没有对应的模块时,则抛出 import 的异常。
也就是说当执行 import utils 这条指令时,Python 会从以下路径中搜索模块 utils.py 。
在当前目录下搜索该模块。
在环境变量 PYTHONPATH 指定的路径列表中依次搜索。
在 Python 安装路径的 lib 库中搜索。
上述路径可以通过变量 sys.path 获得,该变量位于模块 sys 中。sys.path是 Python 的一个系统变量,是 Python 搜索模块的路径列表。其获取的方法如下:
```
import sys

print(sys.path)
```
为了让创建的模块能够被找到,需要将模块放到上述路径中的一个,因为 Python 只会在这些路径中去查找模块,如果没有将模块创建在这些路径中,则找不到对应的模块,也就没办法应用模块中的对象和方法了。
现在呢,我们想要去调用模块 utils 中的 max_num 和 min_num 方法,第一步为导入模块 utils,第二步为调用模块 utils 中的两个方法,具体语句如下:
```
#导入模块utils
import utils

print(utils.max_num(4, 5))
print(utils.min_num(4, 5))
```
下一节接着讲模块创建的其他属性。。。
### 2.2 from <module_name> import <name(s)>
下面,我们一起来看模块导入的另一种方法,直接导入模块中的对象,语句为:from 模块名 import 方法名,我们一起看下方实例:
```
from utils import max_num, min_num

print(max_num(4, 5))
print(min_num(4, 5))
```
使用这种方式导入时,调用 max_num 和 min_num 函数便不需要添加前缀 utils.。
有时候,为了方便,会使用 from <module_name> import * 来导入模块中的所有对象。
```
from utils import *

print(max_num(4, 5))
print(min_num(4, 5))
```
### 2.3 from <module_name> import  as <alt_name>
Python 中模块内的对象和方法也可以有自己的别名,实现语句为: from 模块名 import *** as 别名 ,该命令为导入的对象起一个别名。这样就可以通过别名来使用对象。例如:
```
from utils import max_num as max_n, min_num as min_n

print(max_n(4, 5))
print(min_n(4, 5))
```
在上面的例子中,分别为 max_num,min_num 取了别名 max_n,min_n。这样在调用函数时,便可以使用 max_n,min_n。
### 2.4 import <module_name> as <alt_name>
我们还可以为导入的整个模块起一个别名,这样便可以通过模块的别名来使用模块,使用方法是一样的,都是将 模块名. 作为前缀。例如:
```
import utils as ul

print(ul.max_num(4, 5))
print(ul.min_num(4, 5))
```
在上面的例子中,为模块 utils 取了别名 ul,这样在调用函数时,便可以使用 ul. 前缀。
### 2.5 包含单个类的模块
一起来看下包含单个类的模块,我们创建一个模块(car.py),包含类 car ,语句如下:
```
class Car:
    def __init__(self, mk, md, y, c):
        self.make = mk
        self.model = md
        self.year = y
        self.color = c
        self.mileage = 0

    def get_description(self):
        description = f'{self.year} {self.color} {self.make} {self.model}'
        print(description)

    def get_mileage(self):
        print(f"This car has {self.mileage} miles on it")

    def update_mileage(self, mile):
        self.mileage = mile
```
导入类(my_car.py):
```
from car import Car

my_car = Car('audi', 'a4', 2016, 'white')
my_car.get_description()
my_car.update_mileage(30)
my_car.get_mileage()
```
### 2.6 包含多个类的模块
我们创建模块(car.py),其中包含父类 car 和继承类 Electriccar ,语句如下:
```
class Car:
    def __init__(self, mk, md, y, c):
        self.make = mk
        self.model = md
        self.year = y
        self.color = c
        self.mileage = 0

    def get_description(self):
        description = f'{self.year} {self.color} {self.make} {self.model}'
        print(description)

    def get_mileage(self):
        print(f"This car has {self.mileage} miles on it")

    def update_mileage(self, mile):
        self.mileage = mile


class ElectricCar(Car):
    def __init__(self, mk, md, y, c):
        super().__init__(mk, md, y, c)
        self.battery_size = 100

    def get_battery(self):
        print(f"This car has {self.battery_size} -kWh battery.")
```
导入单个类(my_electirc_car.py):
```
from car import ElectricCar

my_tesla = ElectricCar('tesla', 'model 3', 2018, 'white')
my_tesla.get_description()
my_tesla.get_battery()
```
导入多个类(my_cars.py):
```
from car import ElectricCar, Car

my_car = Car('audi', 'a4', 2016, 'white')
my_car.update_mileage(30)
my_car.get_mileage()

my_tesla = ElectricCar('tesla', 'model 3', 2018, 'white')
my_tesla.get_description()
my_tesla.get_battery()
```
导入整个模块:
```
import car

my_car = car.Car('audi', 'a4', 2016, 'white')
my_car.update_mileage(30)
my_car.get_mileage()

my_tesla = car.ElectricCar('tesla', 'model 3', 2018, 'white')
my_tesla.get_description()
my_tesla.get_battery()
```
导入模块中的全部类:
```
from car import *

my_car = Car('audi', 'a4', 2016, 'white')
my_car.update_mileage(30)
my_car.get_mileage()

my_tesla = ElectricCar('tesla', 'model 3', 2018, 'white')
my_tesla.get_description()
my_tesla.get_battery()
```
## 3. 包
在程序中呢,也会遇到和仓颉一样的问题,就是假设我们开发了一个很庞大的应用程序,程序包含了非常多的模块。随着模块数量的增长,如果将模块都放在同一个目录下,将变得越来越难管理。特别当模块具有相似的名称或相似的功能。这时候我们非常希望对这些模块进行分组管理,Python 中的包实现了对模块分组管理的功能。包的创建非常简单,它利用了操作系统的分层文件结构。我们只要将模块放在一个目录下便可。
![图片.png](https://s2.51cto.com/images/202210/043fbfd21ec09b3acac331fd3b679c0f8b0df5.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
在上图中,目录 pkg 下有两个模块,utils1.py 和 utils2.py,pkg 便是一个包。(包相当于一个文件夹,模块则相当于文件夹中的文件)
两个模块中的语句如下:(语句相当于文件中的内容)
utils1.py:
```
def max_num(a, b):
    if a >= b:
        return a
    else:
        return b


def min_num(a, b):
    if a > b:
        return b
    else:
        return a
```
utils2.py:
```
def sum_num(a, b):
    return a + b


def abs_num(a):
    if a >= 0:
        return a
    else:
        return -a
```
### 3.1 import <module_name>[, <module_name> ...]
导入包中的模块,语法规则为:import 包.模块名,我们一起看下方语句:
```
import pkg.utils1
import pkg.utils2

print(pkg.utils1.max_num(4, 5))
print(pkg.utils2.sum_num(4, 5))
```
导入包 pkg 中的模块 utils1 和模块 utils2,并调用两个模块中的方法,将 pkg.utils1. 作为前缀放在 max_num()方法前,表示是在 pkg 包中的模块 utils1 内的方法。
### 3.2 from <package_name> import <modules_name>[, <module_name> ...]
我们也可以通过 from 语句来实现模块的导入,我们一起看下方语句:
```
from pkg import utils1, utils2

print(utils1.max_num(4, 5))
print(utils2.sum_num(4, 5))
```
### 3.3 from <module_name> import <name(s)>
我们再来一起看下,定义包之后,导入指定模块中的对象,我们看下方语句:
```
from pkg.utils1 import max_num

print(max_num(4, 5))
```
和第二部分模块导入相比,就是在模块名前将包的名字作为前缀 pkg.utils1 来实现的,其余语句均与模块导入一致。
### 3.4 from <module_name> import  as <alt_name>
为模块内的对象和方法设置别名,语句如下:
```
from pkg.utils1 import max_num as max_n

print(max_n(4, 5))
```
### 3.5 from <package_name> import <module_name> as <alt_name>
为导入的整个模块设置别名,语句如下:
```
from pkg import utils1 as ul1

print(ul1.max_num(4, 5))
```
## 4. 小试牛刀
自定义一个模块,并在另一个文件中导入这个模块。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

芯动大师

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

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

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

打赏作者

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

抵扣说明:

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

余额充值