【发布时间】:2015-04-30 06:37:31
【问题描述】:
摘要:
我有一个代表业务单位的 cython 类。此类以纯 cython 样式声明。
在一个项目中,我需要将业务部门映射到数据库。为此,我想导入 .pxd 文件并使用 SQLAlchemy“映射”它。
Cython 定义
让我们假设类设备。该类在 .pxd 中定义了 .pyx 和类接口(因为我需要在其他模块中导入它)。
设备.pxd
cdef class Equipment:
cdef readonly int x
cdef readonly str y
设备.pyx
cdef class Equipment:
def __init__(self, int x, str y):
self.x = x
self.y = y
我编译所有内容并获得一个设备.pyd 文件。到目前为止,还可以。 此文件包含业务逻辑模型,不得更改。
映射
然后在一个应用程序中,我导入设备.pyd 并使用 SQLAlchemy 映射它。
from sqlalchemy import Table, Column, Integer, String
from sqlalchemy.orm import mapper
from equipment import Equipment
metadata = MetaData()
# Table definition
equipment = Table(
'equipment', metadata,
Column('id', Integer, primary_key=True),
Column('x', Integer),
Column('y', String),
)
# Mapping the table definition with the class definition
mapper(Equipment, equipment)
TypeError: can't set attributes of built-in/extension type 'equipment.Equipment'
确实,SQLAlchemy 正在尝试创建 Equipment.c.x、Equipment.c.y、...这在 Cython 中是不可能的,因为它没有在 .pxd 中定义...
那么如何将 Cython 类映射到 SQLAlchemy?
不满意的解决方案
如果我在 .pyx 文件中以 python 模式定义设备类,它可以工作,因为最后,它只是 cython 类定义中的“python”对象。
设备.pyx
class Equipment:
def __init__(self, x, y):
self.x = x
self.y = y
但是我失去了很多功能,这就是我需要纯 Cython 的原因。
谢谢! :-)
-- 编辑部分--
半满意解
保留 .pyx 和 .pxd 文件。从 .pyd 继承。尝试映射。
mapping.py
>from sqlalchemy import Table, Column, Integer, String
from sqlalchemy.orm import mapper
from equipment import Equipment
metadata = MetaData()
# Table definition
equipment = Table(
'equipment', metadata,
Column('id', Integer, primary_key=True),
Column('x', Integer),
Column('y', String),
)
# Inherit Equipment to a mapped class
class EquipmentMapped(Equipment):
def __init__(self, x, y):
super(EquipmentMapped, self).__init__(x, y)
# Mapping the table definition with the class definition
mapper(EquipmentMapped, equipment)
从映射导入 EquipmentMapped
e = EquipmentMapped(2, 3)
打印 e.x
##这是空的!
为了让它工作,我必须将每个属性定义为一个属性!
设备.pxd
cdef class Equipment:
cdef readonly int _x
cdef readonly str _y
设备.pyx
cdef class Equipment:
def __init__(self, int x, str y):
self.x = x
self.y = y
property x:
def __get__(self):
return self._x
def __set__(self, x):
self._x = x
property y:
def __get__(self):
return self._y
def __set__(self, y):
self._y = y
这并不令人满意,因为 :lazy_programmer_mode on: 我在业务逻辑上要做很多更改... :lazy_programmer_mode off:
【问题讨论】:
-
如果你创建一个 cdef 类 EquipmentImpl,然后将 Equipment 作为一个继承自 EquipmentImpl 的常规 Python 类,它会起作用吗?显然会涉及少量开销。
-
@DavidW 确实,我也有同样的想法,但这使事情变得复杂。我用这个解决方案更新我的问题;-)
-
老实说,我有点困惑 - 至少在从 Cython 类继承的属性访问方面对我有用(在 cdef 属性上使用
public或readonly)。我在您的“半令人满意的解决方案”中看到的唯一错误是mapper(Equipment, equipment)可能应该是mapper(EquipmentMapped, equipment)。 -
是的,这是一个错误。应该是EquipmentMapped……我也有点疑惑Cython类继承而来的属性访问。 SQLAlchemy 不应该无法访问它...但是,我已经尝试过,就是这种情况...
标签: python sqlalchemy cython