【问题标题】:Execute python script with same name in different directory在不同目录中执行同名的python脚本
【发布时间】:2018-09-24 09:26:19
【问题描述】:

我的文件结构如下:

答:

|_a.py

|_b.py

乙:

|_a.py

|_b.py

我想动态执行 A/b.py 或 B/b.py。

我正在使用以下代码:

from importlib import import_module    
    path = '/home/username/test/' + module + '/'
    if path not in sys.path:
        sys.path.append(path)
    script = import_module('b', 'Script')
    myClass = getattr(script, 'Script')
    run = myClass()

这样做,如果我运行 B/b.py,然后运行 ​​A/b.py,它将执行 B/b.py 而不是 A/b.py。

第一个运行的脚本将在下一轮执行。

我需要帮助以确保只运行我想要的目录中的文件。

【问题讨论】:

  • 能否提供import_module( ... )的实现和sub的定义?
  • @mangus:已在问题中更新。
  • 如何确定是需要 A/b.py 还是 B/b.py ?如果目录 AB 都在 sys.path 中,则 b.py 不明确。
  • 文件夹和文件名作为参数传递给函数。
  • 如果您先将 A 然后 B 附加到 sys.path,然后是 import b,您将得到 A/b。 py,因为首先附加了 A。然而,可以将append() 包装在if-statement 中:if some_condition : sys.append("A"),但同时附加两者会产生一个模棱两可的b.py。我建议附加到sys.path,而是使用python模块,如下面的回答所示。

标签: python django python-import


【解决方案1】:

我正在对您想要在这里完成的事情做一些假设。即使这不是您想要的,它仍然可能会推动您朝着正确的方向前进:您有两个不同的子目录,AB。它们包含名称相同的脚本 a.pyb.py。根据某些情况,您的脚本应该调用 either A/a.py A/a.py 和那么可能 B/b.py B/b.py

我会将 AB 设置为实际的 Python 模块,也就是说,在这两个文件夹中创建一个 __init__.py 文件。然后有一个主脚本,它以某种方式确定要使用哪个模块..

# root_folder/master.py
import sys
import A
import B

master_script_name = sys.argv[0]

print("I'm the master script : " + str(master_script_name))


def choose_module_A_or_B(arg):
  if arg == "A":
    print(" You chose module A !")
    return A
  return B


module = choose_module_A_or_B("A")

module.b.print_locations()

那么,

# root_folder/A/__init__.py
from A import b

和,

# root_folder/A/b.py
import os
import sys

# how to obtain paths and script name:
folder = os.path.dirname(os.path.realpath(__file__))
script = __file__
parent = os.path.abspath(os.path.join(folder, os.pardir))

def print_locations():
  print(" --> script : " + str(script))
  print(" --> folder : " + str(folder))
  print(" --> parent : " + str(parent))

类似地..

# root_folder/B/__init__.py
from B import b

和,

# root_folder/B/b.py
import os
import sys

# how to obtain paths and script name:
folder = os.path.dirname(os.path.realpath(__file__))
script = __file__
parent = os.path.abspath(os.path.join(folder, os.pardir))

def print_locations():
  print(" --> script : " + str(script))
  print(" --> folder : " + str(folder))
  print(" --> parent : " + str(parent))

输出:

$ python master.py
I'm the master script : master.py
You chose module A !
--> script : A\b.py
--> folder : C:\dev\ScriptTesting\py\script_by_name\A
--> parent : C:\dev\ScriptTesting\py\script_by_name

【讨论】:

    【解决方案2】:

    我已经阅读了您的其他类似question 并提出了一个没有任何预导入的解决方案。这是(恕我直言)高度非pythonic,并且无论如何都可能被视为肮脏的“黑客”。我强烈建议您考虑我的其他答案并正确处理导入。

    您的问题出现是因为您正在破坏命名空间,以及它所珍视的一切。当您使用具有相同签名的函数/方法污染命名空间时,Python 解释器绝对无法区分它们:它解析为第一次导入的那个。

    但是,如上所述,有一种解决方法:(当前)没有办法卸载 python 模块,但您可以使用imp 模块reload 它。从本质上讲,它可以让您清理(重新定义)命名空间。在我的repl.it

    可以找到一个完整的工作示例
    # root_folder/main.py
    import sys
    import imp
    from importlib import import_module
    
    
    def import_script(mod_dir, script):
      sys.path.append(mod_dir)
      mod = imp.reload(import_module(script, 'Script'))
      sys.path.remove(mod_dir)
      return mod
    
    # input:
    mod_dir = "A"
    script = "b"
    
    # import module/script.py
    active_mod = import_script(mod_dir, script)
    
    # use module/script.py
    mod_name = active_mod.get_mod_name()
    print(mod_name) # Prints "A : b.y"
    
    
    # New input: different module/script.py
    mod_dir = "C"
    script = "b"
    
    # import module/script.py
    active_mod = import_script(mod_dir, script)
    
    # use module/script.py
    mod_name = active_mod.get_mod_name()
    print(mod_name) # Prints "C : b.y"
    

    当模块如下所示时,

    # root_folder/A/b.py
    def get_mod_name():
      return "A : b.py"
    

    请注意,每次导入都会加倍,因为每次导入模块(可能有重复的名称)时,还必须重新加载它以清理命名空间。仅仅del 模块是不够的。

    【讨论】:

      猜你喜欢
      • 2018-01-05
      • 2021-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-30
      • 1970-01-01
      • 1970-01-01
      • 2016-12-10
      相关资源
      最近更新 更多