如果您想要 Python 类型类,就像您可能从SQLALchemy
列对象中获得的那样,您将需要构建和维护自己的映射。psycopg2
没有之一,即使在内部。
但是,如果您想要的是一种oid
将原始值转换为 Python 实例的函数的方法,psycopg2.extensions.string_types
那么实际上已经是您所需要的了。它可能看起来只是从oid
名称到名称的映射,但事实并非如此:它的值不是字符串,它们是psycopg2._psycopg.type
. 是时候深入研究一些代码了。
psycopg2
公开一个用于注册新类型转换器的 API,我们可以使用它来追溯涉及类型转换的 C 代码;这以typecastObject
in
typecast.c为中心,不出所料,它映射到psycopg2._psycopg.type
我们在 oldfriend 中找到的string_types
。这个对象包含指向两个函数的指针,pcast
(对于 Python 转换函数)和ccast
(对于 C 转换函数),这似乎是我们想要的——只要选择存在的一个并调用它,问题就解决了。除了它们不在暴露的属性中(name
,它只是一个标签,并且values
,它是一个 oid 列表)。类型确实暴露给 Python 的是__call__
,事实证明,它只是在 和 之间进行pcast
选择ccast
为我们。此方法的文档非常无用,但查看 C 代码进一步表明它需要两个参数:一个包含原始值的字符串和一个游标对象。
>>> 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
在某些情况下可能更方便。
我能想到的需要光标和连接的唯一解决方法是构建一个模拟连接对象。如果它在未连接到实际数据库的情况下公开了所有相关的环境信息,则可以将其附加到游标对象并使用 withstring_types[oid](raw, cur)
或 with cur.cast(oid, raw)
,但该模拟将使用 C 语言构建,并留给读者作为练习。