2017-07-30 130 views
1

是否有可能从python(2.7)中派生类的静态成员初始化基类的静态成员?python静态成员初始化从派生类的静态成员值

也就是说,假设我有一堆的映射存储在一个简单的数据库实体类:以下所有实体有一个名为id字段规则

class EntityA(EntityBase): 
    entityName = 'EntA' # the name of the entity in the DB 
    ... 

class EntityB(EntityBase): 
    entityName = 'EntB' # the name of the entity in the DB 
    ... 

,并假设数据库建立'id_ 实体名称'。因此,'id_EntA'和'id_EntB'分别是EntityA和EntityB的数据库中id字段的名称。

现在,我想从(抽象)基类(EntityBase)只有一次产生这两个名字,但我不能找到一个方法来做到这一点...

我想写类似:

class EntityBase: 
    idFieldName = 'id_' + *derived-class*.entityName 
    ... 

我知道我可以写一个简单的函数,返回连接字符串,但我想这不是我每次调用该函数的时间进行评估。这应该是可能的,因为构建idFieldName值所需的所有信息都存储在静态变量中。

+0

但是'idFieldName'是'entityBase'的一个* static *成员** ** –

+0

如果你想钩入类的创建,请查看元类。 – jonrsharpe

+0

@Willem:是的,我只喜欢它从派生类的静态成员的值中生成一次(在“编译时”)......它有意义吗? – Clonet

回答

0

你可以使用什么是metaclass。元类是某个类所属的类。

然后你可以使用:

class MetaEntityBase(type): 
    def __new__(meta, name, bases, dct): 
     if 'entityName' in dct: 
      dct['idFieldName'] = 'id_'+dct['entityName'] 
     return super(MetaEntityBase,meta).__new__(meta,name,bases,dct) 

然后,你可以写:

class EntityBase: 
    __metaclass__ = MetaEntityBase 

,现在如果我们查询EntityA.idFieldName,我们得到:

>>> EntityA.idFieldName 
'id_EntA' 

在这里,我们使用了if声明首先检查dct。该dct是包含前初始化类成员的字典:所以它包含了所有方法,类字段等

因此,我们检查,如果'entityName'是关键之一(这由此意味着在类级别,它是在某个地方定义的)。如果是这种情况,我们在dct'idFieldName'中添加一个新元素,该元素预先将entityNameid_对齐。当然,如果没有这样的属性entityName

元类的__new__在的建设,而不是对象的施工执行,你可以定义一个else情况下该怎么做。所以除非你动态地创建类,否则它只会被调用一次。

+0

谢谢!这是完美的!我不得不承认,我对Python中的元类没有任何认识,但它似乎是一个非常强大的概念。 – Clonet

+0

有一个问题:我试图注释掉if ...(留下下面一行),我期望它能为派生类工作,但不能用于基础类(我的意思是,我想我可以实例化派生类类但不是基类),但它不适用于两者...为什么? – Clonet

+0

@Clonet:因为在这种情况下永远不会创建“EntityBase”。因为它会出错。结果你不能从这个类中派生出来。一个肮脏的黑客可能是将'entityName'字段添加到'EntityBase'类,或者'__new__'方法中的一些检查。 –