如果您想要 Python 类型类,就像您可能从 SQLALchemy 列对象中获得的那样,您需要构建和维护自己的映射。 psycopg2 没有,即使在内部也是如此。
但是,如果您想要的是一种从 oid 获取将原始值转换为 Python 实例的函数的方法,那么 psycopg2.extensions.string_types 实际上已经是您所需要的。它可能看起来只是从oid 到名称的映射,但事实并非如此:它的值不是字符串,它们是psycopg2._psycopg.type 的实例。是时候深入研究一些代码了。
psycopg2 公开了一个用于注册新类型转换器的 API,我们可以使用它来追溯涉及类型转换的 C 代码;这以typecastObject 为中心
typecast.c,不出所料,它映射到我们在老朋友string_types 中找到的psycopg2._psycopg.type。这个对象包含两个函数的指针,pcast(用于 Python 转换函数)和ccast(用于 C 转换函数),这看起来就像我们想要的那样——只要选择存在的一个并调用它,问题就解决了。除了它们不在暴露的属性中(name,它只是一个标签,values,它是一个 oid 列表)。该类型向 Python 公开的是__call__,事实证明,它只是在pcast 和ccast 之间进行选择。此方法的文档非常无用,但进一步查看 C 代码shows 发现它有两个参数:一个包含原始值的字符串和一个游标对象。
>>> import psycopg2.extensions
>>> cur = something_that_gets_a_cursor_object()
>>> psycopg2.extensions.string_types[23]
<psycopg2._psycopg.type 'INTEGER' at 0xDEADBEEF>
>>> psycopg2.extensions.string_types[23]('100', cur)
100
>>> psycopg2.extensions.string_types[23]('10.0', cur)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '10.0'
>>> string_types[1114]
<psycopg2._psycopg.type 'DATETIME' at 0xDEADBEEF>
>>> string_types[1114]('2018-11-15 21:35:21', cur)
datetime.datetime(2018, 11, 15, 21, 35, 21)
不幸的是,需要一个游标,事实上,并不总是需要一个游标:
>>> string_types[23]('100', None)
100
但是任何必须转换实际字符串(例如varchar)类型的事情都取决于 PostgreSQL 服务器的语言环境,至少在 Python 3 编译中,并且将None 传递给这些施法者不仅会失败——它段错误。您提到的方法cursor.cast(oid, raw) 本质上是psycopg2.extensions.string_types 中脚轮的包装,在某些情况下可能更方便。
我能想到的需要光标和连接的唯一解决方法是构建一个模拟连接对象。如果它在没有连接到实际数据库的情况下暴露了所有相关的环境信息,它可以附加到一个游标对象并与string_types[oid](raw, cur) 或cur.cast(oid, raw) 一起使用,但该模拟将在 C 中构建并保留为给读者练习。