Python重构:整理导入

2 投票
2 回答
1105 浏览
提问于 2025-04-17 07:24

这可能是个新手问题(我从PHP5面向对象转到Python),但我对import语句在整理和重构我们的一些Python模块时有些不确定的地方。

举个例子,我有一个数据库连接工厂模块,它导入了mysqldb,代码大概是这样的:

import MySQLdb as mysql
from MySQLdb import cursors
class ConnectionFactory():
  @staticmethod
  def connect(db_host,db_user,db_pass,db,cursor='DictCursor'):
    connection = mysql.connect(host = db_host,
                   user = db_user,
                   passwd = db_pass,
                   db = db,
                   cursorclass=getattr(mysql.cursors, cursor))
    cur = connection.cursor();
    connection.ping(True)
    return (cur,connection)

首先,为什么第二个导入,专门获取cursors是必要的呢? 我似乎不能直接访问mysql.cursors。

另外,假设另一个模块导入了这个模块来获取数据库连接,然后使用它执行查询。

import ConnectionFactory
def runquery(q):
  try:
    cur,connection = ConnectionFactory.connect(db_host,db_user,db_pass,db)
    cur.execute(q)
    res = cur.fetchall()
    return res
  except Exception as e:
    log(str(e))

理想情况下,捕获的那个异常应该是MySQLdb.Error异常。这是否意味着我也需要在这里导入MySQLdb? 我觉得应该有更优雅的做法。我肯定还没有完全理解Python的思维方式。

最后,假设这两个模块都在另一个父模块中被导入,以便在WSGI中使用(我所有的请求都是通过Werkzeug进来的,然后运行其他模块中的很多方法)

如果WSGI导入了这两个模块,我假设它们各自导入的内容并不在它的命名空间中。那么在多个模块中有相同的导入是个坏习惯吗,如果最终它们会在一个更大的模块中一起使用?

编辑:为了澄清第三个问题,

我有一个特殊的json编码器,它几乎在所有地方都被用作json.dumps()cls参数。

from datetime import datetime
import gnengine
import json

class SpecialEncoder(json.JSONEncoder):
    def default(self,obj):
    if isinstance(obj,set):
        return list(obj)
    elif isinstance(obj,datetime):
        return obj.isoformat()
    elif isinstance(obj,gnengine.searchresult):
        return obj.jsonify()

    return json.JSONEncoder.default(self,obj)

gnengine是我的WSGI,而searchresult是该模块中的一个类型。我在这里导入它是因为它有自己的json方法,我的编码器需要这个方法。但这个编码器显然也被导入到gnengine中。它们实际上是互相导入的。

我的PHP背景告诉我,如果searchresult类型成为一个独立的模块,代表一个对象模型,然后两个模块分别导入它,这样就能解决这个问题。但我不确定这是不是我一个很大的误解。

抱歉把三个问题放在一起,基本上我想问的是关于导入的一般性澄清。我明白命名空间的概念,也知道from name import *是个坏主意,但我就是不明白当几个包一起使用时,如何处理相似的依赖关系才是最佳做法。在Python中,是否期望在多个地方都有相同的import

2 个回答

1
  1. MySQLdb的 __init__.py 文件(或者其他初始化的方法)并没有导入游标(cursors),所以MySQLdb并不知道游标模块的存在,因为它只是自己目录下的一个子目录。这就意味着你需要手动导入这个模块。

  2. 你需要直接从MySQLdb导入异常(exception)。比如说可以用 from MySQLdb import Exception。异常其实就是一些类,它们是Extension类的子类。Python无法处理它不知道的类。这里使用“from”这个词,是为了只导入你需要的部分。

  3. 不,Python的做法是把相同的对象导入到多个不同的文件中,这些文件最终会一起工作。解释器会确保运行时不会出错,也不会覆盖任何东西等等。(试着连续导入同样的东西两次——不会报错,而且你只会得到一个实例)。

1
  1. 我觉得 MySQLdb.cursors 是另一个模块,嵌套的模块需要单独导入。

  2. 如果你想专门捕捉在 MySQLdb 中声明的异常,那你确实需要导入一些东西。如果你想捕捉 任何 异常,那就不需要导入。不过这样做可能不太好,正如 @tkone 在下面的评论中解释的那样。无论如何,我觉得从 MySQLdb 导入一些东西并没有问题——如果你的数据库访问代码没有分散在多个模块中,而是集中在一个数据库访问层里,那么你从 MySQLdb 导入的模块就不会太多。

  3. 我不太明白这个问题。你能再解释一下吗?

撰写回答