hwidgen激活工具是真的吗_你真的会用Python模块与工具包吗?

在开发过程中,我们无法把所有代码、资源都放在同一个文件中。因此,模块导入在编码中是很常见的。无论是C++、Java,还是Python、Go。

可以把不同功能、不同模块进行分离,当使用的时候,可以通过import关键字在一个模块中使用另外一个模块提供的能力,这能够大大提升代码的开发效率。

尤其是对于Python这种对于模块、工具包依赖较强的编程语言,这一点更为突出。

模块导入,这一点在Python中最为常见的东西对于很多人来说都不屑一顾,但是,你真的彻底理解Python中的import吗?

我可以断言,绝大多数Python开发人员只是使用,却不知所以然。

本文,就来详细、彻底的介绍一下Python模块导入的使用。

模块与工具包

模块(modules)和工具包(packages)这2个概念首当其冲,经常被Python开发者混为一谈。

虽然,二者有很多相同之处,但是还是存在一定差异。因此,要想彻底理解import,首先就需要理解模块与工具包的异同点。

模块

Python官网对于模块的定义如下:

模块具有一个包含任意Python对象的命名空间,通常用作Python代码组织单位的对象。

实际上,一个模块通常对应一个.py文件,模块的真正功能是可以将其导入到其他代码中,并重复使用,例如:

>>> import math
>>> math.pi
3.141592653589793

第一行代码,通过import把math模块导入到代码中,通过math.pi来调用pi这一属性。

这里需要注意,这里写的math.pi不仅是单纯的pi,它还把math充当所有属性保持统一的命名空间。命名空间对于保持代码的可读性和组织性非常有用。

你可以利用 dir来查看命名空间的内容:

>>> import math
>>> dir()
['__annotations__', '__builtins__', ..., 'math']

>>> dir(math)
['__doc__', ..., 'nan', 'pi', 'pow', ...]

除了上述直接导入,我们还可以导入模块下特定的部分:

>>> from math import pi
>>> pi
3.141592653589793

>>> math.pi
NameError: name 'math' is not defined

请注意,这里对比于前一种方式已经发生了一些转变。这里的pi是放置在全局命名空间内,而不是math的命名空间内。

同样,首先看一下Python官网对工具包的定义:

一个Python模块,可以包含子模块或递归地包含子包。从技术上讲,包是具有__path__属性的Python模块。

从定义上可以看出,包仍然是模块。但是,它们还是有一定的区别。

从编码上来讲,Python包需要在目录下创建一个名为__init__.py的文件。

导入模块时,通常不会导入子模块和子包,但是,你可以通过添加__init__.py来将需要导入的子模块和子包囊括进去。

绝对导入与相对导入

from ... import ...这种导入当时在代码中经常会遇到,假如,我们有如下工程:

world/

├── africa/
│ ├── __init__.py
│ └── zimbabwe.py

├── europe/
│ ├── __init__.py
│ ├── greece.py
│ ├── norway.py
│ └── spain.py

└── __init__.py

当想要导入africa时可以这样:

from world import africa

也可以这样:

from . import africa

那么这里面的**点(.)**代表什么含义?

这里的点(.)就是一种相对导入,你可以理解为从当前包中导入africa

相反,绝对导入语句中,需要明确命名当前包:

from world import africa

在编码过程中,你可以选择绝对导入,也可以选择相对导入。只不过,PEP 8风格指南中,建议使用绝对导入。

Python导入路径

这是一个需要重点理解的问题,很多开发者从接触Python开始就是用PyCharm,它对于导入路径已经进行了默认的配置,因此,开发者很难遇到无法导入的问题。

但是,当切换到VS Code、Sublime这些需要较多自行配置的开发工具之后,会发现无法导入,或者因为导入工具包带来的调用错误问题。

Python是如何找到它要导入的模块和包的?

你可以试着输出sys.path,你会发现输出列表中主要包含如下3个部分的位置:

  • 当前脚本目录
  • PYTHON_PATH环境变量
  • 其他与安装相关的目录

通常情况下,Python将对列表进行从头开发遍历,从每个位置中寻找给定的模块,直到第一个匹配为止

由于脚本所在目录始终被排在列表的第一位,因此,导入模块时它会首先从当前目录下进行寻找。

所以,一定不要把自己的代码文件名称与工具包重名。

例如,当前目录有一个名为math.py的文件:

# math.py

def double(number):
return 2 * number

这时候,你导入可以按照预期工作:

>>> import math
>>> math.double(3.14)
6.28

但是,它已经覆盖了Python自带的math标准库。如果我们误认为导入的是标准math模块,去调用pisqrt这些方法,则会报错:

>>> math.pi
Traceback (most recent call last):
File "", line 1, in
AttributeError: module 'math' has no attribute 'pi'>>> math'math' from 'math.py'>

因此,为了避免这个问题,一定小心自己开发代码文件的命名。

创建并安装本地工具包

在Python开发过程中,经常会用到pip安装来自PyPI仓库的工具包,它可以用于全局的工程项目。

除了从仓库下载安装工具包,还可以自行在本地创建工具包,并完成安装。

创建本地安装包只需要创建setup.cfgsetup.py两个项目就行:

# setup.cfg

[metadata]
name = local_structure
version = 0.1.0

[options]
packages = structure

# setup.py

import setuptools

setuptools.setup()

这里的版本名称和版本号可以自行选择。

然后,可以执行下方命令,把创建的安装包安装到本地:

$ python -m pip install -e .

导入样式

为了保持代码的可读性和可维护性,PEP 8提出了一些针对模块导入的规则:

  • 将导入放在文件的顶部
  • 每个导入要分行
  • 将导入分组:首先是标准库导入,然后是第三方导入,最后是本地应用程序或库导入
  • 在每个组中按字母顺序排序导入
  • 绝对导入优先于相对导入
  • 避免使用通配符导入from module import *
# Standard library imports
import sys
from typing import Dict, List

# Third party imports
import feedparser
import html2text

# Reader imports
from reader import URL

资源导入

除了模块和工具包,代码开发过程中,还会经常用到外部资源包,针对外部资源包的导入,可以使用importlib.resources

它是Python 3.7中的标准模块,使用它有2点好处:

  • 使得导入方式更加一致
  • 可以更轻松地访问其他包中的资源文件

例如,

>>> from importlib import resources
>>> with resources.open_text("books", "alice_in_wonderland.txt") as fid:
... alice = fid.readlines()

动态导入

Python是一门动态语言,这也是它的主要特点之一。

动态语言使得你可以在程序运行的时候做很多事情,可以添加属性、重新定义方法、更改模块的文档字符串。

例如,通过修改print()函数,使它不做任何操作:

>>> print("Hello dynamic world!")
Hello dynamic world!

>>> # Redefine the built-in print()
>>> print = lambda *args, **kwargs: None

>>> print("Hush, everybody!")
>>> # Nothing is printed

在上述示例中,print函数就被匿名函数重新定义了。

除了这种方法,还有更为易用的动态导入方式,就是利用importlib

先来看一段示例,

# docreader.py

import importlib

module_name = input("Name of module? ")
module = importlib.import_module(module_name)
print(module.__doc__)

import_module()返回可以绑定到任何变量的模块对象。然后,您可以将该变量视为常规导入的模块。

$ python docreader.py
Name of module? math
This module is always available. It provides access to the
mathematical functions defined by the C standard.

$ python docreader.py
Name of module? csv
CSV parsing and writing.

在每种情况下,该模块都是通过动态导入的import_module()

周期性导入

如果两个或者多个模块互相导入时,就会发生周期性导入。

例如,有两个模块yin.pyyang.py

# yin.py

print(f"Hello from yin")
import yang
print(f"Goodbye from yin")

# yang.py

print(f"Hello from yang")
import yin
print(f"Goodbye from yang")

尝试在交互式命令行下导入yin时会发生下面情况:

>>> import yin
Hello from yin
Hello from yang
Goodbye from yang
Goodbye from yin

有些同学会疑惑,这样互相导入,难道不会无限循环下去吗?

这得益于Python的模块缓存机制,在导入yin之后,会首先把它加入到缓存中,后续再导入,会先去参考缓存区域,避免无限循环。


推荐阅读

或许,这是最强大的一款Python GUI工具

8个小技巧教你提升Python代码质量

5款最强且免费的Python IDE

福利

最近我花费了半个月的时间,整理了1份理论+实践的计算机视觉入门教程,这或许是你见过最好的一份CV教程之一。独家打造、完全免费,需要的同学可以扫码添加我的个人微信,发送“CV”获取~

9fd641ef172ec25596ef3955efcb9dcc.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值