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

2024-09-30 18:20:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图从一些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')

我成功地实现了它的一个副本,它似乎在做它应该做的事情,只是它只保存了members变量中的methods,我还需要有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__')

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

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


Tags: nameselfnewreturn定义deftyperesult
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。<;field>;。值:

>>> 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,...)

可能您需要一个工厂,它将基于查询结果和/或表定义构建行类。你知道吗

编辑也许使用__slots__in*行类的想法需要更多的修饰,但这在很大程度上取决于您的实际需要。你知道吗

另外,也许‘Table1.sexo’在我们这个复杂的时代也应该是一个枚举;)

已更新

正如我所评论的,我认为您可能混淆了实例属性和类属性,并且非常希望跟踪后者。实例属性是动态的,可以随时添加、更改或删除,因此尝试使用问题中所示的元类进行此操作是行不通的(不同的实例可能定义了不同的一组实例)。你知道吗

通过重载类的两个特殊方法,即__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))

输出:

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

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

相关问题 更多 >