简体   繁体   English

如何动态地向类添加属性?

[英]How to dynamically add attributes to a class?

I have many similar classes, they all contain their own class attributes: 我有许多类似的类,它们都包含自己的类属性:

class MyClass1(): 
    Context = ClassId1+"CONTEXTSTR"
    SubContext = ClassId1+"SUBCONTEXTSTR"
    UpVal = ClassID+"UPVAL"
    DoenVal = ClassID1+"DOWNVAL"
class MyClass2(): 
    Context = ClassId2+"CONTEXTSTR"
    SubContext = ClassId2+"SUBCONTEXTSTR"
    UpVal = ClassID2+"UPVAL"
    DoenVal = ClassID2+"DOWNVAL"
...

but all this soon becomes annoying and requires a lot of code repetition (error-prone). 但是所有这些很快变得很烦人,并且需要大量的代码重复(容易出错)。

I would like to be able to manipulate a sort of class_variable and to do something like: 我希望能够操纵某种class_variable并执行类似的操作:

class MyClass1():
    self_cls.MakeParameters(ClassId1)

even better if I could use inheritance and pass parameters to classes to do things like: 如果我可以使用继承并将参数传递给类来做类似的事情,那就更好了:

ClassID1 = "test01"    

class MyClass1(BaseClass,<ClassID1>):
    pass

print MyClass1.CONTEXT

obtaining as output "test01CONTEXTSTR" the code. 获取代码“ test01CONTEXTSTR”作为输出。 How to do set the arguments of classes according to a given "template" that takes a parameter? 如何根据具有参数的给定“模板”设置类的参数?

>>> class MyClass:
    def __init__(self, classid):
        self.context = "%s%s" % (classid, "CONTEXTSTR")


>>> somevar = MyClass("someid")
>>> print somevar.context
someidCONTEXTSTR
>>> 

Now if you want to inherit a class, it's a bit different. 现在,如果要继承一个类,则有所不同。 Continuning from above: 从上面继续:

>>> class NewClass(MyClass):
    def __init__(self, classid, secondid):
        MyClass.__init__(self, classid)
        self.secondcontext = "%s_%s" % (secondid, "SECONDCONTEXT")


>>> secondvar = NewClass("someid", "someotherid")
>>> secondvar.context
'someidCONTEXTSTR'
>>> secondvar.secondcontext
'someotherid_SECONDCONTEXT'
>>> 

To auto-set the context (Which I think you're asking?), use keyword arguments: 要自动设置上下文(我想问的是?),请使用关键字参数:

>>> class NewClass(MyClass):
    def __init__(self, newclassid="newclassid", myclassid="myclassid"):
        MyClass.__init__(self, myclassid)
        self.newcontext = "%s%s" % (newclassid, " new context")


>>> NewClass().context
'myclassidCONTEXTSTR'
>>> NewClass().newcontext
'newclassid new context'
>>> NewClass(newclassid="only set this ones id").context
'myclassidCONTEXTSTR'
>>> NewClass(newclassid="only set this ones id").newcontext
'only set this ones id new context'
>>> 

Here I didn't assign the class, I just called it (Hence the brackets) and the keywords filled it in for me. 在这里,我没有分配课程,我只是将其命名(因此在括号中),而关键字为我填充了它。

I think this is what you mean? 我想这就是你的意思?

You can also set it as a keyword for MyClass , and it'll auto-assign if the NewClass doesn't set the variable. 您还可以将其设置为MyClass的关键字,如果NewClass不设置变量,它将自动分配。 I don't think you'd need a code example for that though, but ask if you do. 我认为您不需要为此提供代码示例,但请问是否需要。

I think this is what you're after, if not you'll need to clarify a bit more sorry. 我认为这是您所追求的,否则,您需要澄清一点抱歉。

Of course, you could add the attributes manually to the class like this: 当然,您可以像这样将属性手动添加到类中:

def addToClass(cls, ClassId):
    cls.Context = ClassId1+"CONTEXTSTR"
    cls.SubContext = ClassId1+"SUBCONTEXTSTR"
    cls.UpVal = ClassID+"UPVAL"
    cls.DoenVal = ClassID1+"DOWNVAL"

class NewClass(MyClass):
    ...

Usage: 用法:

addToClass(NewClass, "someid")

But if you think that this is still too 'manual' and you would expect that a great language like Python should provide more and better, then you are right: metaclasses 但是,如果您认为这仍然太“手动”,并且您希望像Python这样的出色语言应该提供更多和更好的功能,那么您是对的: 元类

Use metaclasses 使用元类

You can achieve the wanted behavior using metaclasses (If you don't know what I am talking about I recommend reading the great answer posted in this issue: What is a metaclass in Python? ) 您可以使用元类实现所需的行为(如果您不知道我在说什么,我建议阅读本期发布的好答案: Python中的元类是什么?

Write a Metaclass factory method: 编写一个元类工厂方法:

def getMetaClass(classId):
    class MyMetaClass(type):
        def __new__(cls, name, bases, dct):
            dct["Context"] =  "%sCONTEXTSTR" % classId
            dct["SubContext"] = "%sSUBCONTEXTSTR" % classId
            dct["UpVal"] = "%sUPVAL" % classId
            dct["DownVal"] = "%sDOWNVAL" % classId
            return super(MyMetaClass, cls).__new__(cls, name, bases, dct)
    return MyMetaClass

Define a class based on your Metaclass: 根据您的元类定义一个类:

class MyClass1():
    __metaclass__ = getMetaClass("test01")

Use your class: 使用您的课程:

>>> A.Context
'test01CONTEXTSTR'

Update : If you don't like having this __metaclass__ in every of your classes, you could hide it in a superclass like this (proposed in comment by Anders): 更新 :如果您不喜欢在每个类中都使用此__metaclass__ ,则可以将其隐藏在这样的超类中(由Anders提出):

Metaclass: 元类:

class MyMetaClass(type):
    def __new__(cls, name, bases, dct):
        classId = dct.get("CLASSID", "noClassId")
        dct["Context"] =  "%sCONTEXTSTR" % classId
        dct["SubContext"] = "%sSUBCONTEXTSTR" % classId
        dct["UpVal"] = "%sUPVAL" % classId
        dct["DownVal"] = "%sDOWNVAL" % classId
        return super(MyMetaClass, cls).__new__(cls, name, bases, dct)

Class hiding Meta logic: 类隐藏元逻辑:

class AutoContext:
    __metaclass__ = getMetaClass()

Usage: 用法:

class MyClass1(AutoContext):
    CLASSID = "test01"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM