Ways are also attributes. They just become callable objects.
You can determine if an object can be called using the callable() function:
>>> def foo(): pass ... >>> callable(foo) True >>> callable(1) False
When you call the method, you look at the attribute (a getattr() ) and then call the result:
c.setAttr(newvalue)
- two steps; find the attribute (which in this case searches for the class attribute and processes it as a descriptor), then calls the received object, the method.
When you assign an attribute, you rebuild this name to a new value:
c.setAttr = 'something else'
- operation setattr() .
If you want to intercept the receipt and setting of attributes in instances of your class, you can provide resource access attributes , __getattr__ , __setattr__ and __delattr__ .
If you want to add a method to an instance, you will have to consider the function as a handle object that creates the method object
>>> class Foo: pass ... >>> foo = Foo()
The return value of function.__get__() , if an instance and a class are given, is a related method. Calling this method will invoke the base function with self bound to the instance.
And speaking of descriptors, the property() function also returns a descriptor, allowing you to have functions that behave like attributes; they can intercept the operations getattr() , setattr() and delattr() only for this attribute and turn it into a function call:
>>> class Foo: ... @property ... def bar(self): ... return "Hello World!" ... >>> foo = Foo() >>> foo.bar "Hello World!"
Access to .bar called the get bar attribute, which then calls the original bar method.
In almost all situations, you will not need the callable() function; you document your API, and provide methods and attributes, and your API user will find out without checking each attribute to see if it is callable. In properties, you have the flexibility of providing attributes that are actually callers.