I have a question that is puzzling me recently about which is the best way to retrieve attributes from outside.
Let say I have a class:
class Thing:
def __init__(self, whatever):
self.whatever = whatever
x = Thing('foo')
Now I know that if I want to retrieve whatever attribute I can do this:
x.whatever
I have the habit (probably because I come from other oo languages) to define methods to retrieve class attributes as needed and use them insted of retrieve them directly, like:
class Thing:
def __init__(self, whatever):
self.whatever = whatever
def getWhatever(self):
return self.whatever
In my little experience I've found that using this approach make things easier to mantain in the long term because if I edit the structure of data attributes I have to edit only the specific method.
But since I am not really a python veteran I'd love to know if I am doin' it right or if some other approaches are better and more pythonic. Thoughts?
Defining explicit getters and setters is a bad practice in Python. Instead, use properties:
class Thing(object): # New-style class
def __init__(self, whatever):
self._whatever = whatever
#property
def whatever(self):
return self._whatever # Insert complicated calculation here
So instead of pre-planning by using get methods, just introduce a property when you actually need advanced behavior, and not any earlier.
#phihag has the right idea, and mentions in their answer, but to be more explicit about it: The first step is simply to use the attribute directly:
class Thing(object):
def __init__(self, whatever):
self.whatever = whatever
t = Thing(12)
assert t.whatever == 12
Later, if you find you need to make the whatever attribute more sophisticated, you can turn it into a property:
class Thing(object):
def __init__(self, whatever):
self._whatever = whatever
#property
def whatever(self):
return something_complicated(self._whatever)
t = Thing(12)
assert t.whatever == 12
This way, the calling code doesn't change, and you have a nice clean API to your object.
check python property() http://docs.python.org/library/functions.html#property
Related
Description & What I've tried:
I have seen many posts in stackoverflow about binding methods to class instances (I'm aware there are bunch of duplicates already).
However I havent found a discussion referring to binding a method to the class itself. I can think of workarounds but I'm curious if there is a simple way to achieve following:
import types
def quacks(some_class):
def quack(self, number_of_quacks):
self.number_of_quacks = number_of_quacks
setattr(some_class, "quack", types.MethodType(quack, some_class))
return some_class
#quacks
class Duck:
pass
but above would not work:
d1 = Duck()
d2 = Duck()
d1.quack(1)
d2.quack(2)
print(d2.number_of_quacks)
# 2
print(d1.number_of_quacks)
# 2
because quack is actually modifying the class itself rather than the instance.
There are two workarounds I can think of. Either something like below:
class Duck:
def __init__(self):
setattr(self, "quack", types.MethodType(quack, self))
or something like
class Quacks:
def quack(self, number_of_quacks):
self.number_of_quacks = number_of_quacks
class Duck(Quacks):
pass
Question:
So my question is, is there a simple way to achieve the simple #quacks class decorator I described above?
Why I'm asking:
I intend to create a set of functions to modularly add common methods I use to classes. If I dont quit this project, the list is likely to grow over time and I would prefer to have it look nice on code definition. And as a matter of taste, I think option 1 below looks nicer than option 2:
# option 1
#quacks
#walks
#has_wings
#is_white
#stuff
class Duck:
pass
# option 2
class Duck(
Quacks,
Walks,
HasWings,
IsWhite,
Stuff):
pass
If you don't mind changing your desired syntax completely to get the functionality you want, you can dynamically construct classes with type (see second signature).
The first argument is the name of the class, the second is a tuple of superclasses, and the third is a dictionary of attributes to add.
Duck = type("Duck", (), {
"quack", quack_function,
"walk", walk_function,
...
})
So, instead of decorators that inject the appropriate functionality after creation, you are simply adding the functionality directly at the time of creation. The nice thing about this method is that you can programatically build the attribute dictionary, whereas with decorators you cannot.
Found another workaround, I guess below would do it for me.
def quacks(some_class):
def quack(self, number_of_quacks):
self.number_of_quacks = number_of_quacks
old__init__ = some_class.__init__
def new__init__(self, *args, **kwargs):
setattr(self, "quack", types.MethodType(quack, self))
old__init__(self, *args, **kwargs)
setattr(some_class, "__init__", new__init__)
return some_class
Feel free to add any other alternatives, or if you see any drawbacks with this approach.
Edit: a less hacky way inspired from #SethMMorton's answer:
def quack(self, number_of_quacks):
self.number_of_quacks = number_of_quacks
def add_mixin(some_class, some_fn):
new_class = type(some_class.__name__, (some_class,), {
some_fn.__name__: some_fn
})
return new_class
def quacks(some_class):
return add_mixin(some_class, quack)
#quacks
class Duck:
pass
d1 = Duck()
d2 = Duck()
d1.quack(1)
d2.quack(2)
print(d1.number_of_quacks)
print(d2.number_of_quacks)
When developing code for test automation, I often transform responses from the SUT from XML / JSON / whatever to a Python object model to make working with it afterwards easier.
Since the client should not alter the information stored in the object model, it would make sense to have all instance attributes read-only.
For simple cases, this can be achieved by using a namedtuple from the collections module. But in most cases, a simple namedtuple won't do.
I know that the probably most pythonic way would be to use properties:
class MyReadOnlyClass(object):
def __init__(self, a):
self.__a = a
#property
def a(self):
return self.__a
This is OK if I'm dealing only with a few attributes, but it gets lengthy pretty soon.
So I was wondering if there would be any other acceptable approach? What I came up with was this:
MODE_RO = "ro"
MODE_RW = "rw"
class ReadOnlyBaseClass(object):
__mode = MODE_RW
def __init__(self):
self.__mode = MODE_RO
def __setattr__(self, key, value):
if self.__mode != MODE_RW:
raise AttributeError("May not set attribute")
else:
self.__dict__[key] = value
I could then subclass it and use it like this:
class MyObjectModel(ReadOnlyBaseClass):
def __init__(self, a):
self.a = a
super(MyObjectModel, self).__init__()
After the super call, adding or modifying instance attributes is not possible (... that easily, at least).
A possible caveat I came to think about is that if someone was to modify the __mode attribute and set it to MODE_RO, no new instances could be created. But that seems acceptable since its clearly marked as "private" (in the Pyhon way).
I would be interested if you see any more problems with this solution, or have completely different and better approaches.
Or maybe discourage this at all (with explanation, please)?
I was just wondering if it's considered wildly inappropriate, just messy, or unconventional at all to use the init method to set variables by calling, one after another, the rest of the functions within a class. I have done things like, self.age = ch_age(), where ch_age is a function within the same class, and set more variables the same way, like self.name=ch_name() etc. Also, what about prompting for user input within init specifically to get the arguments with which to call ch_age? The latter feels a little wrong I must say. Any advice, suggestions, admonishments welcome!
I always favor being lazy: if you NEED to initialize everything in the constructor, you should--in a lot of cases, I put a general "reset" method in my class. Then you can call that method in init, and can re-initialize the class instance easily.
But if you don't need those variables initially, I feel it's better to wait to initialize things until you actually need them.
For your specific case
class Blah1(object):
def __init__(self):
self.name=self.ch_name()
def ch_name(self):
return 'Ozzy'
you might as well use the property decorator. The following will have the same effect:
class Blah2(object):
def __init__(self):
pass
#property
def name():
return 'Ozzy'
In both of the implementations above, the following code should not issue any exceptions:
>>> b1 = Blah1()
>>> b2 = Blah2()
>>> assert b1.name == 'Ozzy'
>>> assert b2.name == 'Ozzy'
If you wanted to provide a reset method, it might look something like this:
class Blah3(object):
def __init__(self, name):
self.reset(name)
def reset(self, name):
self.name = 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 reimplements 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.
Is it possible to mutate an object into an instance of a derived class of the initial's object class?
Something like:
class Base():
def __init__(self):
self.a = 1
def mutate(self):
self = Derived()
class Derived(Base):
def __init__(self):
self.b = 2
But that doesn't work.
>>> obj = Base()
>>> obj.mutate()
>>> obj.a
1
>>> obj.b
AttributeError...
If this isn't possible, how should I do otherwise?
My problem is the following:
My Base class is like a "summary", and the Derived class is the "whole thing". Of course getting the "whole thing" is a bit expensive so working on summaries as long as it is possible is the point of having these two classes. But you should be able to get it if you want, and then there's no point in having the summary anymore, so every reference to the summary should now be (or contain, at least) the whole thing. I guess I would have to create a class that can hold both, right?
class Thing():
def __init__(self):
self.summary = Summary()
self.whole = None
def get_whole_thing(self):
self.whole = Whole()
Responding to the original question as posed, changing the mutate method to:
def mutate(self):
self.__class__ = Derived
will do exactly what was requested -- change self's class to be Derived instead of Base. This does not automatically execute Derived.__init__, but if that's desired it can be explicitly called (e.g. as self.__init__() as the second statement in the method).
Whether this is a good approach for the OP's actual problem is a completely different question than the original question, which was
Is it possible to mutate an object
into an instance of a derived class of
the initial's object class?
The answer to this is "yes, it's possible" (and it's done the way I just showed). "Is it the best approach for my specific application problem" is a different question than "is it possible";-)
A general OOP approach would be to make the summary object be a Façade that Delegates the expensive operations to a (dynamically constructed) back-end object. You could even make it totally transparent so that callers of the object don't see that there is anything going on (well, not unless they start timing things of course).
I forgot to say that I also wanted to be able to create a "whole thing" from the start and not a summary if it wasn't needed.
I've finally done it like that:
class Thing():
def __init__(self, summary=False):
if summary:
self.summary = "summary"
self._whole = None
else:
self._whole = "wholething"
#property
def whole(self):
if self._whole: return self._whole
else:
self.__init__()
return self._whole
Works like a charm :)
You cannot assign to self to do what you want, but you can change the class of an object by assigning to self.__class__ in your mutate method.
However this is really bad practice - for your situation delegation is better than inheritance.