There are really two questions here: one about assigning arbitrary attributes to functions, and another about assigning special/double underscore (dunder)/magic attributes.
Assigning attributes to functions is perfectly fine. According to the docs:
Functions are first-class objects.
This does not automatically mean that you can assign attributes to them, but it is a good indication. Functions objects have a writable __dict__
1, which is what makes setting attributes possible. This is an intentional and frequently-used feature. The following SO question elaborates on the subject: Python function attributes - uses and abuses.
The issue with the code shown is with the improper use of dunder attributes. Basically, using dunder attributes for anything other than officially documented use is a bad idea:
Any use of __*__
names, in any context, that does not follow explicitly documented use, is subject to breakage without warning.
There are two particular problems here. The main issue is that adding undocumented dunder attributes can potentially conflict with the normal callable attributes setup by functools.wraps
(listed in the Data Model1). The secondary issue is that adding dunder attributes may add undesirable behaviors to the object in certain cirsumstances, since they are used as flags by the interpreter.
There are a number of alternative naming conventions to be aware of, some of which would have been more appropriate than a dunder method:
- For example, renaming
__method__
to _method
would make it "private by convention", since Python does not really recognize the concept of privacy as such.
- A modified version of
_method
would be _method_
. This is a convention that is used by the builtin enum
package exactly to avoid clobbering reserved names.
- Using a plain name is of course always fine:
method
instead of __method__
.
- A naming scheme that would not work would be
__method
. This triggers name mangling by the interpreter, so the name would be inaccessible as such by the caller. This would be a much worse idea than just using dunder names, which would cause no real problems for any interpreter that I am aware of at the moment.
TL;DR
Assigning attributes to a function is quite useful and fully supported. Assigning to dunder attributes, however, is questionable at best.
1 Scroll down to "Callable Types"