Can the usage of `setattr` (and `getattr`) be considered as bad practice?
getattr, python, setattr
Solution
First, it could definitely make it easier to an existing security hole.
For example, let's say you have code that does `exec`, `eval`, SQL queries or URLs built via string formatting, etc. And let's say you're passing, say, `locals()` or a filtered `__dict__` to the formatting command or as the `eval` context or whatever. Using `setattr` clearly widens the security hole, making it much easier for me to find ways to attack your code, because you can no longer be sure what you're going to be passing to those functions.
But what if you don't do anything else unsafe? Is `setattr` safe then?
Not as bad, but it's still not safe. If I can influence the names of the attributes you're setting, I can, e.g., replace any method I want on your objects.
You can try to protect against this by, e.g., first checking that the old value was not callable, or not a method-type descriptor, or whatever. In the same way you can try to protect against people calling functions in `eval` or putting quotes and semicolons in SQL parameters and so on. This is effectively the same as any of those other cases. And it's a lot harder to try to close all illegitimate paths to an open door, than to just not open the door in the first place.
What if the name never comes from anything that can be influenced by the user?
Well, in that case, why are you using `setattr`? There is no good reason to call `setattr` with a literal.
Anyway, when Lattyware said that there are often better ways to solve the problem at hand, he was almost certainly talking about readability, maintainability, and idiomaticness. But the side effect of using those better ways is that you also often avoid any security implications.
90% of the time, the solution is to use a `dict` instead of an object. Unlike Javascript, they're not the same thing in Python, and they're not meant to be used the same way. A `dict` doesn't have methods, or inheritance, or built-in special names, so you don't have to worry about any of that. It also has a more convenient syntax, where you can say `d['foo']` instead of `setattr(o, 'foo')`. And it's probably more efficient. And so on. But ultimately, the reason to use a `dict` is the conceptual reason: a `dict` is a named collection of values; a class instance is a representation of a model-space object, and those are not the same thing.
So, why does `setattr` even exist?
It's there for the same basic reasons as other low-level features, like being able to access `im_func` or `func_closure`, or having modules like `traceback` and `imp`, or treating special methods just like any other methods, or for that matter `exec` and `eval`.
First, you can build higher-level things out of these low-level tools. For example, to build `collections.namedtuple`, you'd need either `exec` or `setattr`.
Second, you occasionally need to monkey-patch code at runtime because you can't modify it (or maybe even see it) at compile time, and tools like `setattr` can be essential to doing that.
The `setattr` feature—much like `eval`—is often misused by people coming from Javascript, Tcl, or a few other languages. But as long as it can be used for good, you don't want to take it out of the language. (TOOWTDI shouldn't be taken so literally that only one program can ever be written.)
But that doesn't mean you should go around using this stuff whenever possible. You wouldn't write `mylist.__getitem__(slice(1, 10, 2))` instead of `mylist[1:10:2]`. Sometimes, being able to call `__getitem__` directly or build `slice` objects explicitly is a foundation to something that lets the rest of your code be more pythonic, or way to localize a workaround to avoid infecting the rest of your code. Otherwise, there are clearer and simpler ways to do it.
Problem
`setattr` and `getattr` kind of got into my style of programing (mainly scientific stuff, my knowledge about python is self taught). Considering that `exec` and `eval` inherit a potential danger since in some cases they might lead to security issues, I was wondering if for `setattr` the same argument is considered to be valid. (About `getattr` I found this question which contains some info - although the argument is not very convincing.) From what I know, `setattr` can be used without worrying too much, but to be honest I don't trust my python knowledge enough to be sure, and if I'm wrong I'd like to try and get rid of the habit of using `setattr`.