我有一个这样定义的sqlalchemy表
from sqlalchemy.sql.schema import Table
my_table = Table(
"my_table",
metadata,
Column("my_id", BigInteger(), primary_key=True),
...
)
我正在尝试检查该实例,以获取在其创建位置的模块。我尝试使用sqlalchemy.inspect(my_table).__module__
,my_table.__module__
和inspect.getmodule(my_table)
,但是,这三个函数都返回sqlalchemy.sql.schema
,这是定义Table
而不是{{1 }}已定义。
如何获取实例化my_table
的模块的名称?
答案 0 :(得分:1)
您可以通过子类Table
来添加功能。在SQLAlchemy中,Table
专门覆盖Table.__init__()
使其成为无操作:
def __init__(self, *args, **kw):
"""Constructor for :class:`~.schema.Table`.
This method is a no-op. See the top-level
documentation for :class:`~.schema.Table`
for constructor arguments.
"""
# __init__ is overridden to prevent __new__ from
# calling the superclass constructor.
关键在于它不会调用super().__init__()
,以便sqlalchemy可以接受实例化命令,而无论您执行什么操作,都需要维护。
from sqlalchemy.sql.schema import Table
class MyTable(Table):
def __init__(self, *args, **kwargs):
self._where_am_i = __file__
my_table = MyTable(
"my_table",
metadata,
Column("my_id", BigInteger(), primary_key=True)
)
在这种情况下,MyTable.__init__()
仍在阻止超类构造函数,但它还会向实例添加一个属性,该属性将是实例化该类的模块的名称。我专门选择了一个不太明显的属性名称(_where_am_i
),该名称不太可能被sqlalchemy覆盖,并使用__file__
返回模块的路径(但是您可以根据需要进行设置)。
我测试了插入并选择仍然可以使用:
import logging
from sqlalchemy.sql import select
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
logging.basicConfig(level=logging.INFO)
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
conn = engine.connect()
conn.execute(my_table.insert(), [{"my_id": i} for i in range(1, 6)])
s = select([my_table])
result = conn.execute(s)
for row in result:
print(row)
# (1,)
# (2,)
# (3,)
# (4,)
# (5,)
和实例化位置:
print(my_table._where_am_i) # 53302898.py (that's the name of my module).
外部模块:
# external_module.py
from sqlalchemy_app import Base
from sqlalchemy.sql.schema import Table
from sqlalchemy import Column, BigInteger
metadata = Base.metadata
class MyTable(Table):
def __init__(self, *args, **kwargs):
self._where_am_i = __file__
my_table = MyTable(
"my_table",
metadata,
Column("my_id", BigInteger(), primary_key=True)
)
并且:
# 53302898.py
from external_module import my_table
if __name__ == '__main__':
print(my_table._where_am_i) # prints C:\Users\peter_000\OneDrive\git\test\external_module.py
请注意它如何在第一个测试中返回相对文件路径,并在外部模块测试中返回绝对文件路径。您可以在这里阅读有关内容:Python __file__ attribute absolute or relative?,但可以使_where_am_i
属性返回适合您的应用程序的所有内容。
编辑
上述解决方案要求将Table
类内部子类化在组成实例的模块中,否则它将钉住实例化该类的模块,而不是实例。如果只想在项目中对Table
进行子类化,则需要将该位置传递给构造函数。
这有效:
class MyTable(Table):
def __init__(self, *args, _where_am_i=None, **kwargs):
self._where_am_i = _where_am_i
...但是在实例化时会收到警告:
SAWarning: Can't validate argument '_where_am_i'; can't locate any SQLAlchemy dialect named '_where'
。
为避免这种情况,您必须重写sqlalchemy的备用构造函数Table._init()
,删除位置参数,然后委托备份链:
class MyTable(Table):
def _init(self, *args, _where_am_i=None, **kwargs):
self._where_am_i = _where_am_i
super()._init(*args, **kwargs)
从外部模块导入:
# 53302898.py
from external_module import MyTable
my_table = MyTable(
"my_table",
metadata,
Column("my_id", BigInteger(), primary_key=True),
_where_am_i = __file__
)
if __name__ == '__main__':
print(my_table._where_am_i) # 53302898.py
以上所有测试仍然通过。
答案 1 :(得分:0)
不能。如果您参考the Python documentation index,则会看到__module__
的三个条目:一个代表a class attribute,一个代表a function attribute,另一个代表a method attribute。只有那些类型的对象才具有声明其记录的模块。 my_table
都不是;它只是Table
类的一个实例,因此可以在其上找到的唯一__module__
是Table.__module__
。