python中from xxx import xxx的相对引用问题

文章讲述了在阅读Transformers库源码时遇到的相对导入错误,介绍了如何通过设置`__name__`和调整`sys.path`来确保程序正确引用上级和上上级目录的模块。作者给出了一个实际项目的目录结构示例和解决方案。
部署运行你感兴趣的模型镜像

在看Transformers源码时,在modeling_llama.py中有以下代码

from ...activations import ACT2FN
from ...modeling_outputs import BaseModelOutputWithPast, CausalLMOutputWithPast, SequenceClassifierOutputWithPast

发现用了相对引用,引用了前2级目录下的activations文件,直接运行这个modeling_llama.py代码时报错:

ImportError: attempted relative import with no known parent package

表示程序并没找到父目录。
经过查找原因知道,程序运行时需要以当前运行的__name__变量确定目录。此时运行的__name__为modeling_llama(因为相当于将modeling_llama作为了主函数,本来不是),在跑到…时程序不知道上级和上上级目录是什么(因为只有一个modeling_llama),如果想要跑通,需要在modeling_llama.py的import之前指定__name__=‘xxx/xxx/xxx/modeling_llama.py’,第一个xxx表示modeling_llama.py的前2级目录(不包括目前这一级)。完成__name__之后,还需要让程序知道第一个xxx在哪,这时需要用sys.path.append(yyy)指定第一个xxx的父目录(即xxx在yyy里面,yyy为绝对路径)。

这里写一个具体的例子,以下是目录结构:

|-- Test
|   |-- __init__.py
|   |-- m4.py
|   `-- pkg
|       |-- __init__.py
|       |-- m2.py
|       |-- m3.py
|       `-- subpkg
|           |-- __init__.py
|           `-- m1.py
|-- __init__.py
`-- main_cx.py

main_cx是要运行的主文件,m1,m2,m3,m4分别都是main_cx要调用的函数文件,其中m3和m4内容形式是:

def f3():
    print("this is f3 in m3")

m2内容为

from .m3 import f3

def f2():
    print("this is f2 in m2")

若m1要调用m2,m3,m4的函数,最后主程序main_cx.py调用m1,此时m1为

def f1():
    print("this is f1 in m1")

print(__name__)
from ..m2 import f2,f3
from ...m4 import f4

在主程序main_cx中调用m1的所有方法:

from Test.pkg.subpkg.m1 import f1,f2, f3,f4

print(__name__)
f1()
f2()
f3()
f4()

成功运行输出结果为:

__main__
this is f1 in m1
this is f2 in m2
this is f3 in m3
this is f4 in m4

一半来说,项目会有个主程序来运行,不会出现在相同路径下使用相对引用来导包,所以指定__name__和添加path的方法一般不用(不然太麻烦了)。
【注意】如果主函数调用程序都使用了相对引用,并引用了和主函数同一级下的一个方法。应该把那一行相对引用改为绝对引用,比如m1引用的m4和main_cx在同一级目录,那m1的from …m4 import f4要改成 from m4 import f4,因为运行主函数时能直接调用m4。

参考资料:https://www.bilibili.com/video/BV1EK411g7Ff/?spm_id_from=333.337.search-card.all.click&vd_source=6b23f47ec0d092b0587d7d866c9db443

您可能感兴趣的与本文相关的镜像

Python3.10

Python3.10

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

<think>好的,我现在需要回答用户关于Python中直接importfrom...import区别的问题。首先,我得回忆这两种导入方式的基本用法和差异。用户可能想知道它们在语法、作用域、内存使用等方面的不同。 首先,直接import,比如import module,这样导入整个模块,使用时需要module.function()。而from module import function则是导入特定函数,可以直接用function()。这可能导致命名冲突,比如如果当前作用域已经有同名的function,就会被覆盖。 接下来要考虑作用域的问题。直接import需要模块名前缀,避免命名冲突,但代码可能冗长。而from...import可能让代码更简洁,但需要确保导入的名称不会与其他名称冲突。 然后是内存使用方面。直接导入整个模块是否会导致内存占用更高?其实Python的模块是单例的,无论用哪种方式导入,模块只会加载一次。不过from...import会将该函数添加到当前命名空间,可能增加当前命名空间的条目数量,但实际内存差异应该不大。 还要考虑循环导入的问题。两种方式在循环导入时是否有不同的表现?可能需要进一步查证,但通常循环导入问题更多与导入时机有关,而不是导入方式本身。 另外,用户提到的引用[1]和[2]需要合理引用。引用[1]提到模块导入路径的知识,可能与模块搜索路径有关,但可能和问题关联不大。引用[2]关于Python减少代码量,可能和导入方式的选择对代码简洁性的影响有关,可以适当关联。 用户可能还想知道性能差异。一般来说,两种导入方式在性能上差别不大,因为模块只加载一次。不过使用from...import的函数调用可能稍快,因为少了一次属性查找,但差异通常可以忽略不计。 还要注意,使用from...import * 是不推荐的,因为它会导入所有名称,容易引起命名冲突,且代码可读性差。但用户的问题中没有提到这种情况,可能需要说明。 总结区别点:语法、作用域影响、命名冲突风险、代码简洁性、性能(微小差异)、可维护性。需要以清晰的结构呈现这些点,并引用相关资料支持。 可能还需要给出示例代码,比如: 直接importimport math print(math.sqrt(4)) from...importfrom math import sqrt print(sqrt(4)) 这样对比更直观。 最后,确保回答符合用户的要求:结构清晰,分步骤说明,引用正确,并生成相关问题。现在需要检查是否有遗漏点,比如模块重命名(import module as md),但用户的问题可能不涉及这点,不过可以简要提及。 现在组织内容,确保每个部分清晰,并自然引用给定的参考文献。</think>### Python中直接importfrom...import的区别 在Python中,模块导入的两种主要方式(`import module` 和 `from module import name`)有以下核心区别: --- #### 1. **语法与作用域** - **直接导入模块** 使用`import module`时,模块的所有内容需通过模块名前缀访问: ```python import math print(math.sqrt(4)) # 输出: 2.0 ``` 优点:避免命名冲突,明确函数来源。 缺点:代码较长,频繁使用时需重复输入模块名[^1]。 - **从模块导入特定对象** 使用`from module import name`时,可直接使用对象名: ```python from math import sqrt print(sqrt(4)) # 输出: 2.0 ``` 优点:代码简洁,减少冗余。 缺点:若当前命名空间有同名对象,会导致覆盖(例如自定义的`sqrt`函数会被替换)。 --- #### 2. **内存与性能** - **内存占用** 两种方式均会加载整个模块到内存,但Python会缓存已导入的模块,因此多次导入不会增加内存消耗[^2]。 - **性能差异** `from...import`的调用可能略快,因为省去了模块属性的查找步骤,但差异通常可忽略不计。 --- #### 3. **代码可维护性** - **直接导入** 明确标识函数来源,适合大型项目或多人协作,提升代码可读性。 例如:`numpy.array`和`array.array`可通过模块名清晰区分。 - **选择性导入** 适用于频繁使用少数函数的情况,但需谨慎处理命名冲突。 --- #### 4. **其他用法** - **别名导入** 两种方式均可使用别名简化代码: ```python import numpy as np from math import factorial as fac ``` - **通配符导入(不推荐)** `from module import *`会导入所有公共对象,易引发命名冲突,应避免使用。 --- #### 示例对比 | 直接导入 | 选择性导入 | |----------------------------|------------------------------| | `import os` | `from os import path` | | `os.path.join(...)` | `path.join(...)` | | 明确来源,避免冲突 | 代码简洁,但需注意命名空间污染 | --- ### 总结 - **优先使用直接导入**:当需要明确函数来源或避免命名冲突时(例如标准库与第三方库混合使用)。 - **选择性导入适用场景**:代码简洁性要求高,且能确保命名空间安全时。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值