Nyx*_*nyx 0 python sqlalchemy python-3.x
我在一个使用 Sqlalchemy 的 Python 3.6 项目中,我们希望在 Sqlalchemy 上有另一个抽象层。如果需要,这将使我们能够更轻松地将 Sqlalchemy 替换为另一个库。
在这个例子中,它是DbHelper
类:
数据库助手.py
from dbconn import dbconn
from models.animals import Dogs
class DbHelper():
@staticmethod
def get_dog_by_nickname(nickname):
return dbconn.session.query(Dogs).get(nickname)
Run Code Online (Sandbox Code Playgroud)
主文件
from dbhelper import DbHelper
class Dog():
def __init__(self, nickname, breed, age):
self.nickname = nickname
self.breed = breed
self.age = age
@classmethod
def using_nickname(cls, nickname):
row = DbHelper.get_dog_by_nickname(nickname)
return Dog(row.id, row.breed, row.age)
dog = Dog.using_nickname('Tom')
Run Code Online (Sandbox Code Playgroud)
问题:有没有比创建DbHelper
类用作容器并只staticmethod
在其中包含更好的方法?我读过这不是pythonic。
当我们这样做时,将所有staticmethod
函数转换dbhelper.py
为常规方法将填充命名空间from dbhelper import *
是的,有一个比创建一个充满staticmethod
s的类更好的解决方案:只是不要创建这个类,并将它们全部设为模块级函数:
from models.animals import Dogs
dbconn = ...
def get_dog_by_nickname(nickname):
return dbconn.session.query(Dogs).get(nickname)
Run Code Online (Sandbox Code Playgroud)
一个充满staticmethod
s的类的唯一真正意义是为所有这些函数提供一个命名空间。一个模块已经是所有这些函数的命名空间。而且,因为它更直接地被语言语法支持,它意味着当你想明确地这样做时,你可以更容易地绕过命名空间(例如,from dbhelper import ...
)。
你说:
当我们这样做时,将 dbhelper.py 中的所有静态方法函数转换为常规方法将填充命名空间
from dbhelper import *
但答案很明显:不要from dbhelper import *
,只是import dbhelper
。然后,您将使用的所有代码都DbHelper.spam()
变为dbhelper.spam()
.
如果你真的想要两级命名空间,你可以只使用带有子模块的包,而不是带有类的模块。但是我看不出有什么好的理由需要在这里使用两级命名空间。
另一种选择(如 juanpa.arrivillaga 在评论中所建议的)是将其变成一个真正的类,其中每个实例(即使您的实际代码中可能只有一个)都有自己的实例,self.dbconn
而不是使用全局模块。这dbconn
既可以传递到__init__
,也可以直接在 内部构造__init__
。例如:
class DbHelper:
def __init__(self, dbname, otherdbparam):
self.dbconn = dblib.connect(dbname, otherdbparam)
def get_dog_by_nickname(self, nickname):
return self.dbconn.session.query(Dogs).get(nickname)
Run Code Online (Sandbox Code Playgroud)
请注意,我们正在使用普通方法,并访问普通实例变量。这就是类的用途——将某些状态与转换该状态的方法包装在一起。
你如何在两者之间做出决定?好吧,如果dbconn
每个进程只有一个,那么它们在功能上是等效的,但在概念上它们具有不同的含义。如果您将 DbHelper 视为一个数据库,无论是连接还是数据库行为,它都应该是一个类,并且您应该实例化该类的一个实例并以这种方式使用它。如果你认为它只是一堆辅助函数,它们运行在一个独立存在的 dbconn 上,那么它应该是一个扁平模块。
在某些语言(如 Java)中,使用充满 -staticmethod
等价物的类还有另外一点:该语言要么不支持“自由函数”,要么使它们成为与方法完全不同的东西。但这在 Python 中并非如此。
当我们这样做时,您是否希望您的模块导出Dogs
并dbconn
作为界面的“公共”部分?如果没有,您应该__all__
在模块顶部添加一个规范,如下所示:
from models.animals import Dogs
__all__ = [
'get_dog_by_nickname',
...
]
dbconn = ...
def get_dog_by_nickname(nickname):
return dbconn.session.query(Dogs).get(nickname)
Run Code Online (Sandbox Code Playgroud)
或者,用下划线命名所有“私有”模块成员:
from models.animals import Dogs as _Dogs
_dbconn = ...
def get_dog_by_nickname(nickname):
return _dbconn.session.query(_Dogs).get(nickname)
Run Code Online (Sandbox Code Playgroud)
无论哪种方式,您的模块的用户仍然可以访问“私有”数据,但它不会显示在 from dbhelper import *
、help(dbhelper)
、许多 IDE 中的默认自动完成等中。