生成 class 成员的列表,保留其定义顺序
Generate a list of class members that preserves their definition order
我正在尝试根据一些 Python class 的定义自动创建一些 SQL table,我尝试使用 dir()
但是因为它 returns 一个 Python 字典,它没有排序,所以 class 成员的定义顺序丢失了。
在网上阅读我发现了以下here
class OrderedClass(type):
@classmethod
def __prepare__(metacls, name, bases, **kwds):
return collections.OrderedDict()
def __new__(cls, name, bases, namespace, **kwds):
result = type.__new__(cls, name, bases, dict(namespace))
result.members = tuple(namespace)
return result
class A(metaclass=OrderedClass):
def one(self): pass
def two(self): pass
def three(self): pass
def four(self): pass
>>> A.members
('__module__', 'one', 'two', 'three', 'four')
我成功地实现了它的一个副本,它似乎在做它应该做的事情,除了它只是在 members
变量中保存 methods
,而且我还需要 class
成员变量.
问题:
如何获得保留定义顺序的成员变量列表?,我不关心 class 方法,实际上我忽略了它们。
注意:顺序之所以重要是因为 table 将具有引用某些 table 列的约束,并且它们必须在定义列之后,但它们出现在之前。
编辑: 这是我真实程序中的示例class
class SQLTable(type):
@classmethod
def __prepare__(metacls, name, bases, **kwds):
return OrderedDict()
def __new__(cls, name, bases, namespace, **kwds):
result = type.__new__(cls, name, bases, dict(namespace))
result.members = tuple(namespace)
return result
class AreaFisicoAmbiental(metaclass = SQLTable):
def __init__(self, persona, datos):
# edificacion
self.persona = persona
self.tipoEdificacion = datos[0]
self.tipoDeParedes = datos[1]
self.detallesTipoDeParedes = datos[2]
self.tipoDeTecho = datos[3]
self.detallesTipoDeTecho = datos[4]
self.tipoDePiso = datos[5]
self.detallesTipoDePiso = datos[6]
# ambientes
self.problemaDeInfraestructura = datos[7]
self.detallesProblemaDeInfraestructura = datos[9]
self.condicionDeTenencia = datos[10]
self.detallesCondicionDeTenencia = datos[11]
self.sala = toBool(datos[12])
self.comedor = toBool(datos[13])
self.baño = toBool(datos[14])
self.porche = toBool(datos[15])
self.patio = toBool(datos[16])
self.lavandero = toBool(datos[17])
self.habitaciones = toInt(datos[19])
# servicios básicos
self.aguasServidas = toBool(datos[21])
self.aguaPotable = toBool(datos[22])
self.luz = toBool(datos[23])
self.gas = datos[24]
self.internet = toBool(datos[25])
正在做
print(AreaFisicoAmbiental.members)
输出:
('__module__', '__qualname__', '__init__')
变量名称是西班牙语,因为它们的名称将用作 table 列名称,也用作将从数据库结构生成的 Web 应用程序的标签。
我知道 Django 会做类似的事情,但我已经有了做相反事情的数据库检查器,所以我知道我需要类似 Django 的功能来使用我的生成器。
也许,python enum 就足以完成任务。它确实支持 stable order.
DDL 的基本实现如下所示:
from enum import Enum
class Table1(Enum):
nombre = ''
edad = 0
sexo = True
...
然后你可以做:
for prop in Table1:
print(prop)
这给了你
Table1.nombre
Table1.edad
Table1.sexo
如果您需要构建适当的 table 定义,您可以使用 Table1..value:
>>> print(type(Table1.nombre.value))
<class 'str'>
>>> print(type(Table1.edad.value))
<class 'int'>
等等。使用这种技术,您甚至可以 link 一些 table 给其他人,从而构建一整套 table 及其关系的完整定义。
至于数据对象(例如table中的一行,或者查询结果中的一行),这里我觉得你没有任何自己的排序,你只需要维护一个link 到相应的 table class (可以从中恢复订单,但我不认为这是一个请求的选项)。所以这些 classes 可能看起来像这样:
class Table1Row(object):
_table = Table1
__slots__ = tuple(k.name for k Table1)
...
或者干脆
class ASpecificQueryResults(object):
__slots__ = (Table1.nombre.name, Table2.empresa.name,...)
可能您需要一个工厂来根据查询结果 and/or table 定义构建行 classes。
Edit 可能 __slots__
in *Row classes 的想法需要更多润色,但这在很大程度上取决于您的实际需要。
P.S。也许 'Table1.sexo' 在我们这个复杂的时代也应该是一个枚举 ;)
已更新
正如我评论的那样,我认为您可能混淆了实例属性和 class 属性,并且真的想跟踪后者。实例属性是动态的,可以随时添加、更改或删除,因此尝试使用问题中显示的 metaclass 来执行此操作是行不通的(不同的实例可能有不同的一组)定义)。
您可以通过重载 class 的几个特殊方法,即 __setattr__()
和 __delattr__()
并将它们的效果存储在一个私有数据成员,它是 OrderedSet
。这样做将跟踪它们是什么并保留它们的创建顺序。
这两种方法都需要注意不要对私有数据成员本身进行操作。
也就是说,这里有一些说明这种实现的东西:
# -*- coding: iso-8859-1 -*-
# from http://code.activestate.com/recipes/576694
from orderedset import OrderedSet
class AreaFisicoAmbiental(object):
def __init__(self, persona, datos):
self._members = OrderedSet()
self.persona = persona
self.tipoEdificacion = datos[0]
self.tipoDeParedes = datos[1]
def __setattr__(self, name, value):
object.__setattr__(self, name, value)
if name != '_members':
self._members.add(name)
def __delattr__(self, name):
if name != '_members':
object.__delattr__(self, name)
self._members.discard(name)
def methodA(self, value1, value2): # add some members
self.attribute1 = value1
self.attribute2 = value2
def methodB(self):
del self.attribute1 # remove a member
if __name__ == '__main__':
a = AreaFisicoAmbiental('Martineau', ['de albañilería', 'vinilo'])
a.methodA('attribute1 will be deleted', 'but this one will be retained')
a.methodB() # deletes a.attribute1
a.attribute3 = 42 # add an attribute outside the class
print('current members of "a":')
for name in a._members:
print(' {}'.format(name))
输出:
current members of "a":
persona
tipoEdificacion
tipoDeParedes
attribute2
attribute3
最后一点:可以创建一个元class,将这两个方法自动添加到客户端classes,这将使更容易修改现有的 classes.
我正在尝试根据一些 Python class 的定义自动创建一些 SQL table,我尝试使用 dir()
但是因为它 returns 一个 Python 字典,它没有排序,所以 class 成员的定义顺序丢失了。
在网上阅读我发现了以下here
class OrderedClass(type):
@classmethod
def __prepare__(metacls, name, bases, **kwds):
return collections.OrderedDict()
def __new__(cls, name, bases, namespace, **kwds):
result = type.__new__(cls, name, bases, dict(namespace))
result.members = tuple(namespace)
return result
class A(metaclass=OrderedClass):
def one(self): pass
def two(self): pass
def three(self): pass
def four(self): pass
>>> A.members
('__module__', 'one', 'two', 'three', 'four')
我成功地实现了它的一个副本,它似乎在做它应该做的事情,除了它只是在 members
变量中保存 methods
,而且我还需要 class
成员变量.
问题:
如何获得保留定义顺序的成员变量列表?,我不关心 class 方法,实际上我忽略了它们。
注意:顺序之所以重要是因为 table 将具有引用某些 table 列的约束,并且它们必须在定义列之后,但它们出现在之前。
编辑: 这是我真实程序中的示例class
class SQLTable(type):
@classmethod
def __prepare__(metacls, name, bases, **kwds):
return OrderedDict()
def __new__(cls, name, bases, namespace, **kwds):
result = type.__new__(cls, name, bases, dict(namespace))
result.members = tuple(namespace)
return result
class AreaFisicoAmbiental(metaclass = SQLTable):
def __init__(self, persona, datos):
# edificacion
self.persona = persona
self.tipoEdificacion = datos[0]
self.tipoDeParedes = datos[1]
self.detallesTipoDeParedes = datos[2]
self.tipoDeTecho = datos[3]
self.detallesTipoDeTecho = datos[4]
self.tipoDePiso = datos[5]
self.detallesTipoDePiso = datos[6]
# ambientes
self.problemaDeInfraestructura = datos[7]
self.detallesProblemaDeInfraestructura = datos[9]
self.condicionDeTenencia = datos[10]
self.detallesCondicionDeTenencia = datos[11]
self.sala = toBool(datos[12])
self.comedor = toBool(datos[13])
self.baño = toBool(datos[14])
self.porche = toBool(datos[15])
self.patio = toBool(datos[16])
self.lavandero = toBool(datos[17])
self.habitaciones = toInt(datos[19])
# servicios básicos
self.aguasServidas = toBool(datos[21])
self.aguaPotable = toBool(datos[22])
self.luz = toBool(datos[23])
self.gas = datos[24]
self.internet = toBool(datos[25])
正在做
print(AreaFisicoAmbiental.members)
输出:
('__module__', '__qualname__', '__init__')
变量名称是西班牙语,因为它们的名称将用作 table 列名称,也用作将从数据库结构生成的 Web 应用程序的标签。
我知道 Django 会做类似的事情,但我已经有了做相反事情的数据库检查器,所以我知道我需要类似 Django 的功能来使用我的生成器。
也许,python enum 就足以完成任务。它确实支持 stable order.
DDL 的基本实现如下所示:
from enum import Enum
class Table1(Enum):
nombre = ''
edad = 0
sexo = True
...
然后你可以做:
for prop in Table1:
print(prop)
这给了你
Table1.nombre
Table1.edad
Table1.sexo
如果您需要构建适当的 table 定义,您可以使用 Table1.
>>> print(type(Table1.nombre.value))
<class 'str'>
>>> print(type(Table1.edad.value))
<class 'int'>
等等。使用这种技术,您甚至可以 link 一些 table 给其他人,从而构建一整套 table 及其关系的完整定义。
至于数据对象(例如table中的一行,或者查询结果中的一行),这里我觉得你没有任何自己的排序,你只需要维护一个link 到相应的 table class (可以从中恢复订单,但我不认为这是一个请求的选项)。所以这些 classes 可能看起来像这样:
class Table1Row(object):
_table = Table1
__slots__ = tuple(k.name for k Table1)
...
或者干脆
class ASpecificQueryResults(object):
__slots__ = (Table1.nombre.name, Table2.empresa.name,...)
可能您需要一个工厂来根据查询结果 and/or table 定义构建行 classes。
Edit 可能 __slots__
in *Row classes 的想法需要更多润色,但这在很大程度上取决于您的实际需要。
P.S。也许 'Table1.sexo' 在我们这个复杂的时代也应该是一个枚举 ;)
已更新
正如我评论的那样,我认为您可能混淆了实例属性和 class 属性,并且真的想跟踪后者。实例属性是动态的,可以随时添加、更改或删除,因此尝试使用问题中显示的 metaclass 来执行此操作是行不通的(不同的实例可能有不同的一组)定义)。
您可以通过重载 class 的几个特殊方法,即 __setattr__()
和 __delattr__()
并将它们的效果存储在一个私有数据成员,它是 OrderedSet
。这样做将跟踪它们是什么并保留它们的创建顺序。
这两种方法都需要注意不要对私有数据成员本身进行操作。
也就是说,这里有一些说明这种实现的东西:
# -*- coding: iso-8859-1 -*-
# from http://code.activestate.com/recipes/576694
from orderedset import OrderedSet
class AreaFisicoAmbiental(object):
def __init__(self, persona, datos):
self._members = OrderedSet()
self.persona = persona
self.tipoEdificacion = datos[0]
self.tipoDeParedes = datos[1]
def __setattr__(self, name, value):
object.__setattr__(self, name, value)
if name != '_members':
self._members.add(name)
def __delattr__(self, name):
if name != '_members':
object.__delattr__(self, name)
self._members.discard(name)
def methodA(self, value1, value2): # add some members
self.attribute1 = value1
self.attribute2 = value2
def methodB(self):
del self.attribute1 # remove a member
if __name__ == '__main__':
a = AreaFisicoAmbiental('Martineau', ['de albañilería', 'vinilo'])
a.methodA('attribute1 will be deleted', 'but this one will be retained')
a.methodB() # deletes a.attribute1
a.attribute3 = 42 # add an attribute outside the class
print('current members of "a":')
for name in a._members:
print(' {}'.format(name))
输出:
current members of "a":
persona
tipoEdificacion
tipoDeParedes
attribute2
attribute3
最后一点:可以创建一个元class,将这两个方法自动添加到客户端classes,这将使更容易修改现有的 classes.