Reputation: 5544
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 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. How to do set the arguments of classes according to a given "template" that takes a parameter?
Upvotes: 0
Views: 328
Reputation: 18870
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
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?)
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:
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"
Upvotes: 2
Reputation: 4673
>>> 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. 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.
Upvotes: 2