python:两个模块和类在不同的包下具有相同的名称

xt0899hw  于 2023-05-30  发布在  Python
关注(0)|答案(4)|浏览(178)

我已经开始学习python并编写一个练习应用程序。目录结构如下所示

src
 |
 --ShutterDeck
    |
    --Helper
       |
       --User.py -> class User
    --Controller
       |
       --User.py -> class User

src目录位于PYTHONPATH中。在另一个文件中,比如main.py,我想访问两个User类。我该怎么做。
我尝试使用以下方法,但失败了:

import cherrypy
from ShutterDeck.Controller import User
from ShutterDeck.Helper import User

class Root:
  @cherrypy.expose
  def index(self):
    return 'Hello World'

u1=User.User()
u2=User.User()

这肯定是模棱两可的。我能想到的另一种(c++的实现方式)是

import cherrypy
from ShutterDeck import Controller
from ShutterDeck import Helper

class Root:

  @cherrypy.expose
  def index(self):
    return 'Hello World'

u1=Controller.User.User()
u2=Helper.User.User()

但是当上面的脚本运行时,它给出以下错误

u1=Controller.User.User()
AttributeError: 'module' object has no attribute 'User'

我不明白为什么会出错?目录ShutterDeckHelperController中包含__init__.py

w3nuxt5m

w3nuxt5m1#

您希望导入包__init__.py文件中的User模块,以使它们可用作属性。
因此,在Helper/__init_.pyController/__init__.py中添加:

from . import User

这使模块成为包的一个属性,现在您可以这样引用它。
或者,您必须完整导入模块本身:

import ShutterDeck.Controller.User
import ShutterDeck.Helper.User

u1=ShutterDeck.Controller.User.User()
u2=ShutterDeck.Helper.User.User()

所以请用他们的全名来称呼他们。
另一个选项是使用as重命名导入的名称:

from ShutterDeck.Controller import User as ControllerUser
from ShutterDeck.Helper import User as HelperUser

u1 = ControllerUser.User()
u2 = HelperUser.User()
zaq34kh6

zaq34kh62#

一种方法是:

import ShutterDeck.Controller.User
import ShutterDeck.Helper.User

cuser = ShutterDeck.Controller.User.User()
huser = ShutterDeck.Helper.User.User()

你也可以这样做:

from ShutterDeck.Controller.User import User as ControllerUser
from ShutterDeck.Helper.User import User as HelperUser
dz6r00yl

dz6r00yl3#

这可能也有帮助(今天遇到类似的问题):

ShutterDeck
├── Controller
│   ├── __init__.py
│   └── User.py
├── Helper
│   ├── __init__.py
│   └── User.py
└── __init__.py

ShutterDeck/{Controller,Helper}/__init__.py中:

from .User import User

然后:

>>> import ShutterDeck.Helper
>>> helperUser = ShutterDeck.Helper.User()
>>> helperUser
<ShutterDeck.Helper.User.User object at 0x1669b90>
>>> import ShutterDeck.Controller
>>> controllerUser = ShutterDeck.Controller.User()
>>> controllerUser
<ShutterDeck.Controller.User.User object at 0x1669c90>
5tmbdcev

5tmbdcev4#

您可以设计sys.modules来完成此操作。
如果您有两个文件version_file.py,其中包含两个不同模块/项目的版本信息。
导入第一个:

# NB use sys.path.insert(0, ...) to make this path the first path to be searched by the framework
sys.path.insert(0, str(project_a_dir_path)) # NB parent dir of version_file.py   
if 'version_file' in sys.modules:
    # ... deal with this: raise exception, delete key, log, etc. (see explanation below)
project_a_version_file_mod = importlib.import_module('version_file')
# make your own chosen key point to this newly imported module:
sys.modules['project_a_version_file_mod'] = sys.modules['version_file']
del sys.modules['version_file']
# preferably, delete from sys.path if this entry won't be used again:
del sys.path[0]

然后处理另一个:

sys.path.insert(0, str(project_b_dir_path)) # NB parent dir of **its** version_file.py   
project_b_version_file_mod = importlib.import_module('version_file')
sys.modules['project_b_version_file_mod'] = sys.modules['version_file']
del sys.modules['version_file']
# preferably, delete entry from sys.path
del sys.path[0]

现在有两个导入的模块,project_a_version_file_modproject_b_version_file_mod。假设两者都有一个attr“version”,你可以得到它们各自的值:project_a_version_file_mod.versionproject_b_version_file_mod.version
我没有看到任何问题,在这项技术,但会有兴趣听到,如果有人可以指出任何问题。

sys.modules dict的特性和陷阱

注意,根据我的实验,重要的是要知道,如果importlib.import_module查看sys.modules并发现已经有一个键用于要求它添加的下一个模块,它只是忽略了新指令!我觉得这很奇怪,但似乎是这样。
因此,如果您在上面的第一个导入操作中没有删除(del sys.modules['version_file']),则第二个导入操作将在import_module上导入失败(无提示),因此在这种情况下,project_b_version_file_mod实际上也指向版本文件模块project_a_version_file_mod
类似地,如果在第一个操作之前已经有一个键为“version_file”的条目,则导入操作将不会发生。这就是为什么必须处理这种可能性。

sys.path列表的特性和陷阱

NB 2以上,我建议删除添加到sys.path的条目,以便在导入之后导入模块。然后可能会提出这样的异议:“但是假设添加的路径已经存在于sys.path中?“.
答案是sys.pathlist,而不是set,所以实际上可以有多个相同的路径条目,这通常是不希望的,但在这种情况下,这使得处理变得相当简单:通过删除添加的路径,您可以保证将sys.path返回到以前的方式。

相关问题