0

我想编写一个具有良好异常处理功能的函数,以确保在工作环境中安装了所有必要的包。我需要导入两个或更多包并使代码可重用,我想循环从字典中导入的包。

这是我没有循环的代码:

def pkgs_install():
    import subprocess
    import sys

    try:
        import pandas as pd
        print('{} is already installed'.format('Pandas'))
    except ImportError:
        print('{} is not installed and has to be installed'.format('Pandas'))
        subprocess.call([sys.executable, '-m', 'pip', 'install', 'pandas'])
    finally:
        import pandas as pd
        print('{} is properly installed'.format('Pandas'))

    try:
        import numpy
        print('{} is already installed'.format('Numpy'))
    except ImportError:
        print('{} is not installed and has to be installed'.format('Numpy'))
        subprocess.call([sys.executable, '-m', 'pip', 'install', 'numpy'])
    finally:
        import numpy
        print('{} is properly installed'.format('Numpy'))

    print("All packages have been imported. You're good to go!")

这段代码可以正常工作,但现在创建循环要困难得多。我尝试了一段代码,但现在卡住了。这是我的代码:

def pkgs_install():
    import subprocess
    import sys
    pkgs = {'pandas': 'pd', 'numpy': 'np'}
    for p in pkgs:
        s = pkgs[p]
        try:
            import p as s
            print('{} is already installed'.format(p))
        except ImportError:
            print('{} is not installed and has to be installed'.format(p))
            subprocess.call([sys.executable, '-m', 'pip', 'install', p])
        finally:
            import p as s
            print('{} is properly installed'.format(p))

    print("All packages have been imported. You're good to go!")

有人知道如何解决这个问题吗?

非常感谢!

4

2 回答 2

0

您可以使用importlib库按名称导入模块。

import importlib
def pkgs_install():
    import subprocess
    import sys
    pkgs = {'pandas': 'pd', 'numpy': 'np'}
    for p in pkgs:
        s = pkgs[p]
        try:
            s = importlib.import_module(p)
            print('{} is already installed'.format(p))
        except ImportError:
            print('{} is not installed and has to be installed'.format(p))
            subprocess.call([sys.executable, '-m', 'pip', 'install', p])
        finally:
            s = importlib.import_module(p)
            print('{} is properly installed'.format(p))

    print("All packages have been imported. You're good to go!")
于 2020-03-27T15:32:37.040 回答
0

我建议不要尝试pip从这样的 Python 程序中动态调用。有2个原因:

  1. 对用户环境进行如此侵入性的更改似乎是一种不好的形式。让用户自己决定是否要安装这些库。
  2. 用户系统可能有许多不同的配置,我们不可能解释所有可能的设置1。这冒着破坏东西并留下一团糟的风险(见第 1 点)

让我问你这个:假设这个模块需要安装一些库,然后发现它不可用。那是否可以恢复(通过强制安装丢失的库以外的其他方式)?通过可恢复,我的意思是:模块仍然能够做一些有用的事情,还是唯一的结果是显示错误消息并退出?通常,缺少库是一个致命错误,因为我们导入东西是因为我们需要它们而不是为了好玩。

如果无法恢复,请不要抓住它。这会抑制有用的调试信息,否则用户将能够采取行动。如果您需要捕获它(可能显示自定义错误消息或将异常记录到文件中),则在块raise末尾出现相同的异常。except

我认为最好的办法就是import像往常一样做,如果失败了,就引发异常。例外不是敌人,它们不是失败的标志2。他们所做的只是传递与预期不符的程序状态的信息,并且在必要时让它们冒泡并没有错。


编辑
在对此答案的评论中,OP 添加了更多信息,这解释了本练习的真正目标是允许将 python 程序以一种使其可供其他人使用的方式进行打包,而无需强迫他们安装额外的模块。

这是一个非常普遍的需求,并且有一个非常成熟且易于使用的解决方案:PyInstaller。它适用于多个目标平台,并支持所有常见的 Python 版本。它是开源的,可从 PyPI 安装:

pip install pyinstaller

它支持 matplotlib、numpy 和可能的 pandas(虽然没有列为支持的包,但我必须假设如果前 2 个包有效,pandas 也可以)。

这是官方文档站点


1:可能模块包含 C 扩展并需要编译器。也许用户已将特定版本的库安装到非标准位置。也许你的包需要的版本与其他已经安装的库不兼容。也许[可能出错的几十件事情中的任何一件]......

2:我应该说,你计划的例外不是敌人。知道可能会引发哪些异常并做出故意决定让某些异常未经处理地传播是绝对可以的。如果一个程序引发了计划的异常,那就是另一回事了……

于 2020-03-27T15:12:50.177 回答