如何编写导入功能?

时间:2018-11-23 22:19:59

标签: python import

我正在做一个我的小组项目,代码的每个部分都很混乱。我想提高导入的可读性。我认为20行混乱的导入会损害代码的主要结构。

这是导入的一部分:

import datetime
import os
import json
import re
import psycopg2 as dbapi2
from datetime import datetime
from datetime import date
from flask import Flask, jsonify
from flask import redirect

我想用诸如此类的东西导入所有这些

import importLibs
importLibs()

为此,我尝试了How to make global imports from a function?的解决方案,并提出了以下解决方案:

def importLibs():
    globals()['datetime'  ]       = __import__('datetime'         )
    globals()['os'        ]       = __import__('os'               )
    globals()['json'      ]       = __import__('json'             )
    globals()['re'        ]       = __import__('re'               )
    globals()['dbapi2'    ]       = __import__('psycopg2'         )
    globals()['date'      ]       = __import__('datetime'         )
    globals()['Flask'     ]       = __import__('flask.Flask'      )
    globals()['jsonify'   ]       = __import__('flask.jsonify'    )
    globals()['redirect'  ]       = __import__('flask.redirect'   )

但是它失败了:

ModuleNotFoundError: No module named 'flask.Flask'

3 个答案:

答案 0 :(得分:2)

警告:您所做的几乎肯定是个坏主意。


错误的原因是flask.Flask是一个类,而不是一个模块。

如果您真的必须这样做,则可以尝试:

__import__('flask').Flask
__import__('flask').jsonify
__import__('flask').redirect

但是,这严重严重损害了代码的可读性。

通过将导入布置在模块顶部,您可以立即查看您的代码正在使用什么。通过将其移动到一个单独的文件中,您可以隐藏代码的依赖项,并使其更难以理解正在发生的事情。

将导入放在文件顶部是我能想到的每种语言的标准做法。考虑一下当他们看到这个时会想到什么。他们为什么这样做呢?看起来真的很复杂。有什么我想念的吗?他们为什么不像其他所有人一样只使用import语句?

到他们弄清楚您在做什么时,他们已经浪费了5分钟的时间。 这很分散注意力

最后,请记住,您编写的代码越复杂,爬虫的空间就越大!

答案 1 :(得分:0)

不要解决不存在的问题。

每个Python程序员都已经完全知道对导入的期望。骇人听闻的importLibs()函数只会增加间接级别和不必要的复杂性。

您应遵循PEP8中提供的进口标准指南:https://www.python.org/dev/peps/pep-0008/#imports

对于有问题的特定导入,您可能需要按字母顺序排列并将外部模块与标准库模块分开。除此之外,别管他们

以下是看起来很容易读懂(和标准)的轻微清理:

import datetime
import json
import os
import re
from datetime import date

import psycopg2 as dbapi2
from flask import Flask, jsonify, redirect

答案 2 :(得分:0)

首先,惯用的Python(“ pythonic”)样式是使用20行显式import语句。如果您不尝试规避正常的导入机制,则静态分析工具的功能通常会更好。某些PyCharm等IDE可以为您排序。

像这样的动态导入如果不实际运行代码就很难理解。

也就是说,某些库确实使用这样的运行时导入。有时,您需要导入的内容取决于运行时条件,因此值得学习动态导入的工作方式。

第二,通常不建议内置__import__,因为当模块嵌套时,它不会为您处理.。请改用importlib.import_module。但是对于Flask来说,它不是一个模块,而是一个类,所以请使用import_module('flask').Flask

第三,模块不可调用。您不能像您建议的那样简单地导入并调用它。

import importLibs
importLibs()

应该是类似

from my_imports import importLibs

可以通过使sys.modules发生突变来将任意对象放入导入缓存,因此您可以通过这种方式使直接导入成为可调用的。众所周知,模块会在导入时用其他东西代替自己。请负责任地使用,因为在没有实际运行代码的情况下,这又很难推理。

第四,globals()函数引用定义模块的全局变量。不是调用它的模块。因此,您不能只from my_imports import importLibs然后期望它将内容导入当前模块。它们将进入my_imports模块内部。至少有两种方法可以解决这个问题。

一种方法是在函数中添加某种globals_dict参数,并在函数上设置全局变量,而不是globals()。然后,您将其称为importLibs(globals())。这样,它将使用来自调用模块的全局指令而不是定义(my_imports)模块。

另一种方法是使用inspect模块上升到堆栈框架并找到调用方的模块以获取其全局变量。这样,您将不必显式传递它,而只需使用importLibs()。但是这种自动魔术更易碎,如果您以某种方式在另一个模块中间接调用它,它可能会破坏。


另一种选择是将所有内容导入您的第三个模块my_imports,在那里提供__all__,然后使用

from my_imports import *

如果您仔细地管理全局名称空间,甚至不需要__all__。不建议使用星号导入,因为显式导入更容易以静态方式进行推理,但是某些库确实以这种方式工作。


最后,您可以使用短名称创建一个模块,将所有内容导入其中,然后只需通过.从任何地方访问内容,例如

import my

my.Flask

同样,一些库以这种方式工作,例如tk。