Python中模块与包有相同名字的处理方法

前言

在编程开发中,个人觉得,只要按照规范去做,很少会出问题。刚开始学习一门技术时,的确会遇到很多的坑。踩的坑多了,这是好事,会学到更多东西,也会越来越觉得按照规范做的重要性,规范的制定就是用来规避问题的。有时候确实应该听听有经验人的建议,不要一意孤行。这好像不是本文的重点,其实我重点是想表达,尽量按规范做事,这样会少走很多弯路。

我现在使用的主力编程语言是 Python,在接触 Python 至今,我感觉我踩的坑还是极少的,基本上没有遇到什么奇怪的问题。实际上,这并不是一件好事,不踩坑,很多躺在暗处的知识点你不会了解,所以也很难成长。幸好,有一些会踩坑的同事。

一同事问我,在 Python 中,如果一个模块和一个包同名时,是不是只能导入包,如果要导入模块该怎么办。他的意思大概是这样的,在项目的同一级目录下,有一个 foo.py 文件和一个 foo/ 目录,如果 import foo 会导入 foo/ 的内容而不是 foo.py 的内容。

被问到这个问题时,我首先感觉到的是诧异,这明显是存在歧义的。如果是我,肯定不会把模块名和包名设计成一样的名字,因为本质上来说在导入的时候没法区分到底要导入谁。除非系统有特别的规定,例如,规定这种情况只能导入包。

我的潜意识里认为这里应该报错,Python 解释器不知道要导入谁。但是,同事告诉我,别人的代码是这么写的,而且在这种情况下会默认导入包。那就是可以的咯,而且解释器已经规定这种情况会总是导入包。

为了验证下这一点,我写了个简单的项目,项目结构如下:

.
├── main.py
└── same
 ├── api
 │ └── __init__.py
 ├── auth
 │ └── __init__.py
 ├── auth.py
 └── __init__.py

其中:

same/api/__init__/py 的内容:

from .. import auth

same/auth/__init__.py 的内容:

auth_str = "This is str in package!"

same/auth.py 的内容:

auth_str = "This is str in module!"

main.py 的内容:

from __future__ import print_function

from same.api import auth

# Script starts from here

if __name__ == "__main__":
 print(auth.auth_str)

稍微有些复杂,哈哈,主要是同事那儿大致的结构是这样的,这里是为更好的模拟下。我在 same.auth 包中定义了一个 auth_str 字符串,又在同名的 same.auth 模块中定义了一个同名的 auth_str 字符串,然后在 same.api 包尝试导入 auth,最后在 main.py 尝试输出 same.api.auth.auth_str,看看到底哪个字符串会被打印。同时尝试用 Python2 和 Python3 执行 main.py,得到的结果都是:

This is str in package!

这里验证了我们的猜想是正确的,解释器的确只导入了包中内容。但是,我并不知道是否有官方的资料说明就是这样的,所以我不敢确信,万一这只是巧合呢。

于是,我开始查资料来验证这一结论。我就说实话吧,对于一个英文水平烂到你无法想象的我,只能先尝试用百度搜索下答案了。事实是,用百度往往都是遗憾的。片刻后,无果,我只能硬着头皮尝试英文搜索了。于是,在 stackoverflow 上找到了如下提问:

How python deals with module and package having the same name?

其中有一个人回答说 Python 官方文档中在描述模块搜索路径时提到了这一点:https://docs.python.org/3/tutorial/modules.html#the-module-search-path.

文档中有如下一段描述:

After initialization, Python programs can modify sys.path. The directory containing the script being run is placed at the beginning of the search path, ahead of the standard library path. This means that scripts in that directory will be loaded instead of modules of the same name in the library directory. This is an error unless the replacement is intended. See section Standard Modules for more information.

也就是说,目录在库的搜索路径下会首先被搜索,这就意味着目录会代替同名的模块被加载。

这下终于放心了,之前的结论得到证实。在 Python 中,如果尝试导入同名的模块和包时,包会被导入。这种情况下,如果想要导入模块,恐怕要用一些 ‘hack' 的方法,上面提到的 stackoverflow 帖下有一些示例可以参考。当然,最好的方法是避免这样的设计,这样你就不会花那么长时间去查资料,也不会花那么长时间来写类似于本文的文章。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • python中安装模块包版本冲突问题的解决

    问题 最近在工作中遇到一个问题,在安装python软件包的时候,经常会遇类似这样一个问题.比如对于ipython,机子本身安装的版本是1.2.1,显然太低,不足以跑jupyter,尝试着用pip安装,却发现下载的过程一路畅通,但是安装的时候却总是会报这样一个错误. 错误提示如下: ......'Not uninstalling ipython at /usr/lib/python2.7/dist-packages, owned by OS'...... 最终显示了ipython已经成功安装,但是

  • Python程序设计入门(4)模块和包

    Python语言功能非常强大,除了类之外,还有模块和包的概念,这有点像perl,此处简单说说包和模块. 一.Python中的模块 模块--其实就是我们说的库(lib)的概念,不过它不仅只是可以包含一系列函数,也可以包含类,python里是没有像C语言之类,直接include某文件的,包正是这种类似的东西. Python 引入模块的方法有两种: 1.import 模块名(实际是对应的就是 文件名.py ) 2.模块名 = __import__("模块文件名(不带扩展名)") 也可以&qu

  • Python中的包和模块实例

    一.实例和结果 1)实例的结构和具体的文件: 复制代码 代码如下: PyPackage │  PyCommonM.py │  __init__.py │ ├─p1Package │      P1M.py │      P1MC.py │      __init__.py │ └─p2        P2.py        P2M.py 2)PyCommonM.py 复制代码 代码如下: def PyCommonMF():  print "PyCommonMF" 3) P1M.py:

  • Python中使用语句导入模块或包的机制研究

    这篇文章讨论了Python的from <module> import *和from <package> import *,它们怎么执行以及为什么使用这种语法(也许)是一个坏主意. 从一个模块导入全部 from <module> import * means意味着"我希望能访问<module>中我有权限访问的全部名称".例如以下代码something.py: # something.py public_variable = 42 _priv

  • Python中的模块和包概念介绍

    模块概述 如果说模块是按照逻辑来组织 Python 代码的方法, 那么文件便是物理层上组织模块的方法. 因此, **一个文件被看作是一个独立模块, 一个模块也可以被看作是一个文件. 模块的文件名就是模 块的名字加上扩展名 .py . 与其它可以导入类(class)的语言不同,在 Python 中你导入的是模块或模块属性**. 模块名称空间 一个名称空间就是一个名称到对象的关系映射. 导入模块 导入模块整体(import) 方式一 复制代码 代码如下: import module1 import

  • Python中模块与包有相同名字的处理方法

    前言 在编程开发中,个人觉得,只要按照规范去做,很少会出问题.刚开始学习一门技术时,的确会遇到很多的坑.踩的坑多了,这是好事,会学到更多东西,也会越来越觉得按照规范做的重要性,规范的制定就是用来规避问题的.有时候确实应该听听有经验人的建议,不要一意孤行.这好像不是本文的重点,其实我重点是想表达,尽量按规范做事,这样会少走很多弯路. 我现在使用的主力编程语言是 Python,在接触 Python 至今,我感觉我踩的坑还是极少的,基本上没有遇到什么奇怪的问题.实际上,这并不是一件好事,不踩坑,很多躺

  • Python中的datetime包与time包包和模块详情

    目录 一.datetime包 1.timedelta(params…)得到一个时间增量对象 2.timezone(timedelta)+timedelta(params…)创建时区对象 3.datetime模块 datetime.strftime(fmt)datetime时间对象转字符串 datetime.strptime(date_string,fmt)字符串转成datetime时间对象 datetime.timestamp(datetime_obj)将datetime时间对象转换成秒级时间戳

  • python中模块导入模式详解

    目录 模块导入 1.1 import导入模块 1.2 from 模块名 import 导入模板的方法 1.3 as 关键字 OS模块操作文件 OS模块的作用 模块的制作.发布.安装 3.1 模块制作 3.2 模块的分 3.3 示例 3.4 测试方法 3.5 all魔术方法 模块导入 1.1 import导入模块 所谓的模块其实就是一个外部的工具包,其中存在的其实就是Python文件,这些文件都实现了某种特定的功能,我们导入包之后直接使用即可,非常的方便. 在开发中使用最多的就是使用: impor

  • 一文掌握python中的时间包

    目录 python中的时间包 datetime时间包 获取当前时间 获取时间间隔 时间对象转时间字符串 时间字符串转时间对象 扩展–时间格式字符 时间戳–timestamp time时间包 获取当前时间戳 获取本地时间 暂停函数sleep time中的strftime和strptime python中的时间包 datetime时间包 datetime包是日期与时间的结合体(date&time) 可以获取当前时间 可以获取时间间隔 可以将时间对象转换成时间字符串 可以将字符串转成时间类型 导入da

  • python中模块的__all__属性详解

    python模块中的__all__属性,可用于模块导入时限制,如: from module import * 此时被导入模块若定义了__all__属性,则只有__all__内指定的属性.方法.类可被导入. 若没定义,则导入模块内的所有公有属性,方法和类 # kk.py class A(): def __init__(self,name,age): self.name=name self.age=age class B(): def __init__(self,name,id): self.nam

  • 关于python中模块和重载的问题

    模块和重载 简单来讲,任意一个以.py结尾的python文件都是一个模块.例如有A.py和B.py两个文件.在A中可以通过导入B来读取B模块定义的内容,导入操作本质上就是载入另一个文件. 基于模块的模型是python程序架构背后的核心思想. 一个大型python程序往往以多个模块文件的形式出现,并且从其它模块导入工具.但是通常会指定一个模块文件作为主文件(也叫顶层文件),该文件启动之后,就会运行整个程序.除了顶层文件之外的其他文件都是导入模块. 导入操作将会导致模块中的代码被运行,因此导入文件也

  • Python中打包和解包(*和**)的使用详解

    目录 一.打包参数 二.解包参数 三.几点注意 *和**在函数的定义和调用阶段,有着不同的功能,并且,*和**不能离开函数使用! 一.打包参数 * 的作用:在函数定义中,收集所有位置参数到一个新的元组,并将整个元组赋值给变量args >>> def f(*args): # * 在函数定义中使用 print(args) >>> f() () >>> f(1) (1,) >>> f(1, 2, 3, 4) (1, 2, 3, 4) 我们可

  • Python中requests库的基本概念与具体使用方法

    目录 一. 基本概念 1. 简介 2. 获取 3. http 协议 3.1 URL 3.2 常用 http 请求方法 二. 使用方法 1. 基本语法 2. 具体使用方法 2.1 get 2.2 post 2.3 response 2.4 head 2.5 put 总结 一. 基本概念 1. 简介 requests 模块是 python 基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库.它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP 测

  • Python中的Socket 与 ScoketServer 通信及遇到问题解决方法

    Socket有一个缓冲区,缓冲区是一个流,先进先出,发送和取出的可自定义大小的,如果取出的数据未取完缓冲区,则可能存在数据怠慢.其中[recv(1024)]表示从缓冲区里取最大为1024个字节,但实际取值大小是不确定的,推荐其值小于等于8192. 黏包问题: Socket发送两条连续数据时,可能最终会拼接成一条进行发送 解决方法一: 两条数据间进行延时发送,如[tiem.sleep(0.5) #延时0.5s] 解决方法二: 每次发送后等待对方确认接收信息数据,发送一条后就立即接收等待 解决方法三

  • 在python中实现将一张图片剪切成四份的方法

    如下所示: import cv2 # [1]导入OpenCv开源库 import numpy as np image_path = "F:\\11111111111111111111111111111\\100000.jpg" srcImg = cv2.imread(image_path) # [2]将图片加载到内存 cv2.namedWindow("[srcImg]", cv2.WINDOW_AUTOSIZE) # [3]创建显示窗口 cv2.imshow(&qu

随机推荐