Flask - 如何在大型应用中阻止循环导入?

时间:2017-09-18 18:31:50

标签: python-3.x flask

我正在Flask的一个项目上工作,我在循环导入方面遇到了麻烦。

我的应用程序结构如下所示:

.
├── api
│   ├── __init__.py
│   ├── schema.py
│   └── sender.py
├── app.py
├── config.py
├── README.md
├── run.sh
├── static
│   ├── css
│   │   ├── base.css
│   │   ├── index.css
│   │   └── model.css
│   └── index.html
├── templates
│   ├── base.html
│   ├── model.html
│   ├── schema_add.html
│   ├── schema.html
│   └── table.html
└── views
    ├── auth.py
    ├── error_handler.py
    ├── __init__.py
    ├── model.py
    ├── schema.py
    └── table.py

源代码可在this

上找到
Here's a trace of error:
    Traceback (most recent call last):
  File "./../anton_temp/app.py", line 3, in <module>
    from views import *
  File 
"/home/shubham1172/Documents/Anton/anton_temp/views/__init__.py", line 
16, in <module>
    from .auth import *
  File "/home/shubham1172/Documents/Anton/anton_temp/views/auth.py", 
line 4, in <module>
    from app import setConnection, getConnection, closeConnection
  File "/home/shubham1172/Documents/Anton/anton_temp/app.py", line 4, 
in <module>
    from api import *
  File "/home/shubham1172/Documents/Anton/anton_temp/api/__init__.py", 
line 13, in <module>
    from .schema import *
  File "/home/shubham1172/Documents/Anton/anton_temp/api/schema.py", 
line 5, in <module>
    from app import getConnection
ImportError: cannot import name 'getConnection'

问题是,我必须在我的应用中包含我的蓝图(views和api)。 这些蓝图的 init 文件还包括py文件,而py文件又必须包含应用程序中的一些功能。

我在某处读取了将这些函数包含在外部文件中,比如说extension.py,然后从蓝图中调用它,但我在app中的函数包含对其app对象的'app'的引用。

我该如何解决这个问题?

修改

正如所指出的,我将不得不重构我的代码。 This显示了同一问题的示例,并给出了解决方案。但是,我的扩展中的功能需要调用应用程序的配置,即

A.py

import B
from C import dependency

B.py

from C import dependency

C.py

def dependency():
    #Use A.config here <----------
    pass

有什么方法可以解决这个问题吗?

修改

我通过重构代码解决了这个问题。 我发现app.config可以通过一个简单的函数调用导出到另一个文件。

C.py

obj = None
def setObj(object):
    obj = object

def dependency():
    #use obj now
    pass    
现在可以从A.py!

调用

setObj(obj)

2 个答案:

答案 0 :(得分:0)

尝试避免此问题的一种方法是捕获所有循环导入例外:

>>> try:
>>>    from mylib import myclass
>>> except:
>>>    pass
>>> try:
>>>     from mylib2 import myclass2
>>> except:
>>>     pass

另一种解决方案,我也不喜欢,在您进行操作时会导入包装。因此,您应该在需要它的函数中进行导入:

>>> def func1():
>>>     from mylib import myclass
>>>     c = myclass()
>>>     ....
>>>
>>> def func2():
>>>     from mylib2 import myclass2
>>>     ...

另一种可能的方法是在创建app对象后导入所有蓝图的依赖关系。这意味着您可以安全地导入对象&#34; app&#34;因为您延迟了导入依赖项。

在你的main.py(或主文件)中:

>>> from flask import Flask
>>> 
>>> app = Flask()
>>> 
>>> from . import views  # safe to import "app" from views.py now!
>>> 
>>> a = 3  # this generates circular dependency error from views.py. it hasn't been creted yet!!

在views.py中:

>>> from .main import app # safe to import "app". 
>>> 
>>> app.route("/")
>>> def hello_world():
>>>     ...

正如您所知,当views.py为&#34; app&#34;调用main.py时对象,它已经被创建了。

但是,最好的解决方案是重新设计您的应用。换句话说,如果您在应用中发现了这个问题,那么很明显,您没有设计它并且需要不同的文件系统架构(甚至是不同的架构)。

您还可以参考以下链接中提供的工厂设计模式:

http://flask.pocoo.org/docs/0.12/patterns/appfactories/

就个人而言,我使用工厂,到目前为止我还没有遇到任何问题。

答案 1 :(得分:0)

应用配置导入问题可由烧瓶config dictionary处理。

在模块C.py中,您可以使用随书current_app object访问应用程序配置。

如果A.py是您的主应用文件:

# A.py
from flask import Flask
app = Flask(__name__
app.config['MY_CONFIG_KEY'] = 'something'

然后您可以在C.py中访问应用的配置,如下所示:

# C.py
from flask import current_app

def dependency():
    v = current_app.config['MY_CONFIG_KEY']

需要注意的一件重要事情是,解决循环依赖关系的方法是使用应用程序工厂和蓝图。