creating Python classes with arbitrarily substituted attribute name
I apologize for not giving this question a better title; the reason that I am posting it is that I don't even have the correct terminology to know what I am looking for.
I have defined a class with an attribute 'spam':
def SpamClass(object): def __init__(self, arg): self.spam = arg def __str__(self): return self.spam
I want to create a (sub/sibling?)class that has exactly the same functionality, but with an attribute named 'eggs' instead of 'spam':
def EggsClass(object): def __init__(self, arg): self.eggs = arg def __str__(self): return self.eggs
To generalize, how do I create functionally-identical classes with arbitrary attribute names? When the class has complicated behavior, it seems silly to duplicate code.
Update: I agree that this smells like bad design. To clarify, I'm not trying to solve a particular problem in this stupid way. I just want to know how to arbitrarily name the (non-magic) contents of an object's __dict__
while preserving functionality. Consider something like the keys()
method for dict
-like objects. People create various classes with keys()
methods that behave according to convention, and the naming convention is a Good Thing. But the name is arbitrary. How can I make a class with a spam()
method that exactly replaces keys()
without manually substituting /keys/spam/ in the source?
Overloading __getattr__
and friends to reference the generic attribute seems inelegant and brittle to me. If a subclass re开发者_JAVA百科implements these methods, it must accommodate this behavior. I would rather have it appear to the user that there is simply a base class with a named attribute that can be accessed naively.
Actually, I can think of a plausible use case. Suppose that you want a mixin class that confers a special attribute and some closely related methods that manipulate or depend upon this attribute. A user may want to name this special attribute differently for different classes (to match names in the real-world problem domain or to avoid name collisions) while reusing the underlying behavior.
Here is a way to get the effect I think you want.
Define a generic class with a generic attribute name. Then in each sub class follow the advice in http://docs.python.org/reference/datamodel.html#customizing-attribute-access to make the attribute look externally like it is called whatever you want it called.
Your description of what you do feels like it has a "code smell" to me, I'd suggest reviewing your design very carefully to see whether this is really what you want to do. But you can make it work with my suggestion.
You can also create a super-class with all common stuff and then sub-classes with specific attributes.
Or even:
def SuperClass(object):
specific_attribute = 'unset'
def __init__(self, arg):
setattr(self, specific_attribute, arg)
def __str__(self):
return getattr(self, specific_attribute)
def EggClass(SuperClass):
specific_attribute = 'eggs'
Have you considered not overcomplicating things and just create one class? (since they are identical anyway)
class FoodClass(object):
def __init__(self, foodname, arg):
self.attrs = {foodname: arg}
self.foodname = foodname
def __str__(self):
return self.attrs[foodname]
If you want some nice constructors, just create them separately:
def make_eggs(arg):
return FoodClass('eggs', arg)
def make_spam(arg):
return FoodClass('spam', arg)
To create attributes during runtime, just add them in self.__dict__['foo'] = 'I'm foo'
in the class code.
精彩评论