【python】模块和包

python模块和包


​ 在python中,一个程序由简单的程序可以由变量,函数,类组成,也可以说函数也是一个变量(对象), 类也是一个变量(对象),其次有了模块的概念,以 .py结束的一个文本文件就可以称为一个模块,模块是我们保存代码的最小的一个单位,

​ 一个模块可以称之为一个细胞,而由很多细胞组成的器官,可以称之为包。一个包包含了很多的模块。

​ python之所以强大,就是因为第三方别人编写好的包我们可以直接导入使用,life is short, we need python,那么怎么导入别人编写好的包呢?python在安装的过程中,只会提供一些基础的包,比如math包,random包等等……如果我们需要更多的别人写好的模块,我们需要使用pip模块管理工具下载别人写好的模块。pip就约等于一个管理插件的工具。
在这里插入图片描述
​ 有过C++基础的人应该知道C++中的命名空间的概念(namespace),在python中,一个模块不允许出现重名的情况,如果出现了重名的情况,那么后面的定义的变量会覆盖前面的,但是如果是不同的模块中,python就允许出现重名的情况,所以一个模块也能够称为一个命名空间

​ 以下的测试代码在python的一个轻量IDE-pycharm下编写测试,pycharm下载安装教程,当使用pycharm创建好一个项目文件之后,会出现两个文件夹,不能够删除

​ .idea文件夹和venv文件夹,为python的运行环境文件夹,不能够删除。
在这里插入图片描述

​ 接下来,我们创建两个文件夹,test01文件夹和test02文件夹,和idea和venv文件夹属于同级目录下,并且在test01目录下创建一个t1.py文件,在test02目录下创建一个c1.py文件,整个文件体系如下:
在这里插入图片描述
为了使用的方便,都使用以下图片表示

在这里插入图片描述

1. 模块的导入以及使用

1.1 import的使用

我们在一个模块中使用import导入别的模块写好的函数,类等…

  • 我们在test01包中的t1.py模块编写一个变量a,一个add()函数,和一个People类
  • 通过import把t1中编写的函数,变量,类导入到test02中的c1模块中
  • 在c1中使用导入的模块

test01.t1:

a = 10

def add(c: int, b: int) -> int:
   return c + b


class People(object):
   def __init__(self, age: float, name: str):
       self.age = age
       self.name = name

   def __str__(self):
       return f'我叫{self.name}, 我今年{self.age}岁了'

我们在test01文件夹下的t1.py模块中定义了一个变量,一个函数和一个类,我们在test02文件夹下的c1.py模块下导入test01.t1这个模块

test02.c1:

import test01.t1
# 把test01.t1模块导入到我们的c1模块中
print(test01.t1.a)
print(test01.t1.add(10, 20))
tom = test01.t1.People(20, 'tom')
print(tom)

程序输出为:

10
30
我叫tom, 我今年20岁了

通过以上步骤,我们成功实现了自己编写的模块的导入和使用

import的导入一定是具体到模块的,比如下面的代码,我仅仅导入test01,而不是test01.t1

import test01
# 导入的并非一个模块,而是一个包
print(test01.t1.a)
print(test01.t1.add(10, 20))
tom = test01.t1.People(20, 'tom')
print(tom)

那么整个代码就会报错

1.2 as(取别名的使用)

现在我们在test01文件夹下面再新建一个文件夹,test03,在test03包中再编写一个模块
在这里插入图片描述

现在我们需要编写这个m1.py文件,并且在c1.py中调用这个模块

test03.m1.py

a = 10


def add(c: int, b: int) -> int:
    return c + b


class People(object):
    def __init__(self, age: float, name: str):
        self.age = age
        self.name = name

    def __str__(self):
        return f'我叫{self.name}, 我今年{self.age}岁了'

直接复制test01中的t1.py模块的代码到test03中的m1.py模块中

现在在c1.py模块中调用上面模块中的代码

c1.py

import test01.test03.m1

print(test01.test03.m1.a)
print(test01.test03.m1.add(10, 20))
tom = test01.test03.m1.People(20, 'tom')
print(tom)

程序输出为:

10
30
我叫tom, 我今年20岁了

可以看出来,这里嵌套了四层,每次我们需要调用这个嵌套中的模块,都需要写很多层嵌套,对于我们来说十分麻烦,于是就有了取别名

import test01.test03.m1 as m
#这里使用as进行取名,把原来的很多层嵌套进行替换
print(m.a)
print(m.add(10, 20))
tom = m.People(20, 'tom')
print(tom)

程序输出为:

10
30
我叫tom, 我今年20岁了

也能够得到正确的结果

1.3 from…import…

现在又有了一个新的问题,为了更加的方便,连点运算符都不想使用,有没有更加简单的方法

还真有! 我们的口号是:life is short, we need python!

依然从上面的test03.m1.py模块中导入

test02.c1.py

from test01.test03.m1 import a, add

print(a)
print(add(10, 20))

在这里,我们直接把test01.test03.m1模块中的a, 和 add()导入,并且不需要加任何前缀就能使用

程序输出为:

10
30

是不是十分方便,那如果想导入的东西很多,比如想要再导入一个People类,那么应该怎么办

可以这样from test01.test03.m1 import a, add, People

可是我还是觉得麻烦,这边使用 * 号一键全部导入

from test01.test03.m1 import *

print(a)
print(add(10, 20))
tom = People(20, 'tom')
print(tom)

程序输出为:

10
30
我叫tom, 我今年20岁了

是不是十分方便,哈哈,但是不推荐使用 * 号,因为如果你导入的包是你不太熟悉的,那么你可能会翻车车什么的🚗

还是推荐你需要什么,就导入什么,别一股脑全部导入

1.4 来自面向对象的思考

​ 【小故事】想象一下,你是一个模块,你自己有三种属性,车,房子和老婆。你有一个好基友,也就是另外一个模块,他需要导入你的车子使用(这个可以有),你能够把车子借出给朋友,这是你朋友能导入你这个模块的一些内容,那你的朋友能不能导入你的房子呢?额,十分要好的好基友,问题也不大,那么问题来了,你朋友能导入你老婆嘛?【💚要坚强💚]

​ 在我们看来,某个模块能不能导入我们编写的模块,我们想让他导入,他才能导入,我们想要隐藏的一些东西,外界不能够随便导入

__all__:填写一个列表,这个列表中的元素是外界能访问的元素,列表之外的不能够被其他模块访问,下面对test01.t1.py进行限制

test01.t1.py

__all__ = ['a', 'add']
#People类不在列表中
a = 10
def add(c: int, b: int) -> int:
   return c + b


class People(object):
   def __init__(self, age: float, name: str):
       self.age = age
       self.name = name

   def __str__(self):
       return f'我叫{self.name}, 我今年{self.age}岁了'

同时,在test02.c1.py中,我们这样写

from test01.t1.py import People
#8好意思,会报错,这是我老婆你不能访问

这也是面向对象的很重要的思想,我想让外界访问什么,外界只能访问什么

2. python中的包

python中的包其实可以当作一个文件夹,一个文件夹下面有许多的模块,但是python中的包和文件夹有一些不一样的属性,

__init__.py:“到我了?”

我:对,到你了!

2.1 __init__.py

在python中,我们新建一个包的时候
在这里插入图片描述

​ 上面的例子中,我们的所说的包都是Directory,也就是test01, test02, test03,他们都是普通的包,严格来说,python中的包(python Package)在新建了之后,子目录下会自动产生一个__init__.py文件,当我们在其他模块导入这个新建的python包,__init__.py模块中的代码会自动执行(本来是没有代码的,但是我们可以在里面写代码)

新建的python包我们取名叫做test04,在自动生成的目录下的__init__.py文件中写几句代码

在这里插入图片描述

好了,我们现在在test02.c1.py模块导入test04包,会发现导入之后啥也没干,控制台会自动输出life is short,we need python

​ 在这里我的思考,python中万物皆是对象,Python中的包也是一个对象,这个__init__.py估计就是这个包对象的def __init__(self), 当我们生成这个python的对象,这个对象的构造函数会自动运行

2.2 __init__.py的用法

OK,现在我们在test04文件夹下新建三个python的模块

  • k1
  • k2
  • k3

当这四个模块都需要使用random(随机数模块), math(数学模块),如下图:

在这里插入图片描述

按照我们的想法,是不是每个模块都导入一次random包和math包呢?那这样每个包导入一次,重复的代码也太多了8,没错,我们的__init__.py就可以用来解决重复代码这个问题,我们只需要在__init__.py导入一次这些random和math包,k1, k2, k3就能够使用这些模块了

测试代码如下:

__init__.py

import random
import math

k1.py

from test04 import *
print(math.sqrt(9))
#计算出9的算数平方根
print(random.randint(10, 50))
#生成一个10到50的随机数

k2.py

from test04 import *
print(math.sqrt(9))
#计算出9的算数平方根
print(random.randint(10, 50))
#生成一个10到50的随机数

k3.py

from test04 import *
print(math.sqrt(9))
#计算出9的算数平方根
print(random.randint(10, 50))
#生成一个10到50的随机数

我们只需要导入在__init__.py中导入一次这些需要在k1, k2, k3都需要使用的公共的包,就可以避免k1, k2, k3重复多次的导入公共的包了

2.3 导入嵌套bug

现在我们在test04包中有了k1, k2, k3三个模块,如下图:

在这里插入图片描述

因为python是一门动态的语言,所以在程序执行的过程中,我们运行任何一个模块,比如我们运行k1,

  • 编译器发现自己需要导入k2这个模块,于是编译器去就导入k2
  • 编译器导入k2的时候,发现k2需要去导入k3这个模块,然后编译器就去导入k3
  • 编译器导入k3的时候,发现居然要导入k1,然后k1不得不去导入k1
  • 编译器去导入k1的时候,发现k1要导入k2,然后编译器去导入k2
  • ……
  • ……
  • 编译器:“我fffffffff”

这个时候,我们运行任何模块都会陷入死循环

如下:
在这里插入图片描述

3. pip – 模块管理工具

以下是bilibili献给新一代的演讲《后浪》名场面,用来形容python再合适不过了
在这里插入图片描述

​ python之所以强大,很主要的一个原因是python本身具有很强大的python库,并且因为python本身是开源的,所以第三方库特别的多,使得管理文档,执行单元测试、数据库、web浏览器、电子邮件、密码学、图形用户界面和更多的东西被更容易调用。我们只需要去调用别人已经写好的库并且使用,不用关心具体的实现,如果要是什么都要自己实现,那……

pip就是这样一个工具,用来下载安装别人提供的第三方库,通过pip我们就可以尽情的享用现代文明的成果。

在pycharm中,点击下图中的终端,就可以使用pip命令

在这里插入图片描述

以下是pip相关的一些命令

命令

  • pip install / uninstall 第三方库名

查看我们都白嫖了那些库

  • pip list

看看我们还有那些库能够白嫖

  • help(‘modules’) ,单引号别忘记了

至于安装速度慢的问题,因为是国外的网站,所以访问比较慢,换成国内的镜像网站,比如阿里源,或者清华源就可以解决下载速度慢的问题;以下是python换源详细教程,用以解决第三方库安装速度慢的问题;

如果pip版本较低,需要更新,复制以下代码:

python -m pip install --upgrade pip

在终端运行就可以把pip升级到最新版本;

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值