生成保留其定义顺序的类成员列表

时间:2015-04-10 19:49:04

标签: python python-3.x introspection metaclass

我试图从一些Python类的定义中自动创建一些SQL表,我尝试使用dir()但是因为它返回了一个Python字典,所以它没有被排序所以这个类的定义顺序成员们迷路了。

在互联网上阅读我发现了以下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')

我成功地实现了它的副本,它似乎正在做它应该做的事情,除了它只保存methods变量中的members,我还需要 class成员变量

问题

我如何获得保留其定义顺序的成员变量列表?我不关心类方法,我实际上忽略了它们。

注意:订单之所以重要,是因为这些表会有一些引用某些表列的约束,并且它们必须在定义列之后继续,但它们之前会出现。< / p>

编辑:这是我真实程序中的示例类

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__')

变量名称是西班牙语,因为它们的名称将用作表列名称,也可以用作将从数据库结构生成的Web应用程序的标签。

我知道Django做了这样的事情,但我已经有了我的数据库检查器,它做了相反的事情,所以我知道我需要一个类似Django的功能来使用我的生成器。

2 个答案:

答案 0 :(得分:2)

也许,python enum就足够了。实际上它支持稳定的订单。

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

如果您需要构建正确的表定义,可以使用Table1。&lt; field&gt; .value:

>>> print(type(Table1.nombre.value))
<class 'str'>
>>> print(type(Table1.edad.value))
<class 'int'>

等等。使用这种技术,您甚至可以将一些表链接到其他表,从而构建一整套表及其关系的完整定义。

对于数据对象(例如表中的行或查询结果的行),这里我认为您没有任何自己的排序,您只需要维护到相应表类的链接(从中订单可以恢复,但我不认为这是一个请求的选项)。所以这些类看起来像这样:

class Table1Row(object):
    _table = Table1
    __slots__ = tuple(k.name for k Table1)
    ...

或只是

class ASpecificQueryResults(object):
   __slots__ = (Table1.nombre.name, Table2.empresa.name,...)

可能你需要一个可以根据查询结果和/或表定义构建行类的工厂。

编辑可能在* Row类中使用__slots__的想法需要更多优点,但这在很大程度上取决于您的实际需求。

P.S。也许'Table1.sexo'在复杂的时代也应该是一个枚举;)

答案 1 :(得分:2)

<强>更新

正如我评论的那样,我认为你可能会将实例属性与类属性混淆,并且真的想跟踪后者。实例属性是动态的,可以随时添加,更改或删除,因此尝试使用您的问题中显示的元类来执行此操作将无效(并且不同的实例可能会定义不同的组)。

您可以通过重载几个类的特殊方法(即__setattr__()__delattr__()并将其效果存储在私有数据成员# -*- 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)) 中来跟踪其创建和删除。 {3}}。这样做会跟踪它们是什么,并保持它们的创建顺序。

这两种方法都需要注意不要对私有数据成员本身进行操作。

那就是说,这是一个说明这种实现的东西:

current members of "a":
  persona
  tipoEdificacion
  tipoDeParedes
  attribute2
  attribute3

输出:

{{1}}

最后一点: 可以创建一个自动将这两种方法添加到客户端类的元类,这样可以更容易地修改现有的类。