Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Using setattr in a __init__ to add dynamic attributes is a violation of object oriented methodology?

In other object oriented languages the attributes cannot be dynamically added to a class. How will code know how to interactive with an object of a given class if the attributes are dynamically assigned and can vary. I believe this shouldn't be taught in python object oriented course as it encourages the development of hard to debug code. To add more attributes and/or behaviour in object oriented languages you need to create a subclass. I come from a java background, I realise that python is meant to be a more dynamic language, but this is violating object oriented principles and should not be encouraged. Is there a good reason for this being used? What are the scenarios to validate its use? What does python standards say about it?

3 Answers

Kenneth Love
STAFF
Kenneth Love
Treehouse Guest Teacher

The standards and styles of one language don't necessarily apply to another language. Also, there's no firm, inter-language standard for how object-oriented design (or any other design pattern) has to be implemented. Live by the rules of the language you're writing.

In Python, using setattr inside of __init__ is the cleanest and best way to apply any extra attributes given to your instance. Python has no rules about not adding attributes to an instance after the fact and you can add attributes to any object you want at any time you want. That's how the language is designed.

Subclassing in Python is a totally different mentality than it is in Java, too. Most of the time, subclassing in Python is done for convenience sake and not for specificity. This consistently throws Java developers (and seems to have for you) but, again, live by the rules of the language you're writing. You'll have much more struggle if you try to write Python like it's Java, or Java like it's Python, than you will if you just embrace the pros and cons of each language.

I do realise that python is a dynamic language and meant to be used in a more dynamic way. But when I have read the documentation and found other examples of classes in python community they do not use this setattr approach. They use the standard approach of encapsulation and defining attributes on self within init. This is a standard principle of object oriented programming. Encapsulating data with setters and getters, behaviour via methods effecting the state of the object. You cannot have dynamic attributes added to an object and still be able to consistently use it. There is no context with which to effect the dynamic state. How can encapsulation be followed if the state varies? How can behaviour be applied to it through methods?

Also this opens up subtle hard to find bugs through typos!

All examples I've seen have used the pattern of creating attributes within the init method. I have not seen this setattr pattern in the examples or the python documentation on classes. That is why I think on a theoretical and practical (best practices) stance it shouldn't be encouraged for new python developers. It encourages a bad practice. The dynamic nature of python aside, classes are there to give it a more deterministic approach to OO. Its not the same as prototyping languages like lua and javascript where classes and OO is more loosely applied.

I'm not convinced with the argument that 'its different with python'. OO principles are the same, and community and official examples don't follow this style, which suggests that the consensus of opinion would be not to use setattr in such a way. And definitely not to be taught/encouraged for beginners in a course.

Kenneth Love
STAFF
Kenneth Love
Treehouse Guest Teacher

Yes, it's illogical to think that some other piece of software will care about the arbitrary attribute you gave to your object, whether after the fact or during initialization. As the Zen of Python says "explicit is better than implicit", so you shouldn't expect anything that wasn't explicitly configured to work. Just because I gave my str instance an attribute of reversed=True doesn't mean it should be reversed.

The setattr pattern isn't in the official tutorial for classes but neither are properties, magic methods, or class methods. It's an introductory tutorial, it won't cover most uses or approaches. Also, the Python docs are pretty sparse about __init__, __new__, and setattr. Again, they give the basic uses for them and that's it. Pretty common for Python docs, actually.

Looking for examples, I like this one. Yes, it's from 2009 but setattr and __init__ are both pretty old so I think it's acceptable. Ned Batchelder and Lennart Regebro, two people that do quite a bit of Python development and education both weigh in on the question. Note that the original example uses setattr and, oddly, no one calls it out (except for not doing exactly what they're wanting in the original question).

Reuven Lerner, also a common Python educator, shows an example of using it. In fact, they go even further and use the inspect module to do a bit more. Definitely overkill for a beginner class, though.

And even the amazing attrs project uses it to make setting attributes on a class easier and faster.

I 100% agree that you shouldn't use only setattr to set the attributes on your class instances. It is, however, fine to use for catching extra arguments that someone wants to toss onto an instance. Should you limit __init__ to only arguments you'll explicitly set on the instance? Maybe. I think that's going to come down to how your code is going to be used and by whom. Is it completely irresponsible to use setattr inside of __init__? No, not at all.