A
So a method is actually an attribute?The short answer is Yeah.for the level at which the question is focused for practical purposes is. Technically anything that can be referenced through an object using notation .nombre (dotted expression) is considered an attributeThat includes methods.IMPORTANTThis may seem to contradict the concepts of attribute and method in the POO paradigm, in which a attribute is a characteristic that describes a particular object while a method is something that that this object can do. This separation is maintained conceptually at a high level in Python, conceptually a method and attribute are not of course the same, but as far as language is concerned and how the POO is implemented in Python the separation is not so clear, rather the oppositeand that's what the question is about and it's what you're trying to answer in this answer.The attribute method I define in class A (method = funcionIs it a method?Yes, it is. Although the concept of method is normally restricted to "function defined in the body of a class", for practical and non-conceptual purposes, it is a method. You can define methods outside the class, even in another module and then link them like that. Or even after the class definition:class Test:
def foo(self):
print(f"Hola, soy un método de {self} definido de forma 'normal'")
>>> inst = Test()
>>> inst.foo
<bound method Test.foo of <main.Test object at 0x7f13658fac70>>
>>> inst.foo()
Hola, soy un método de <main.Test object at 0x7f13658fac70> definido de forma 'normal'
>>> inst.bar()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute 'bar'
>>> def bar(self):
print(f"Soy un método de {self} definido a 'distancia'")
>>> Test.bar = bar
>>> inst.bar
<bound method bar of <main.Test object at 0x7f13658fac70>>
>>> inst.bar()
Soy un método de <main.Test object at 0x7f13658fac70> definido a 'distancia'
Take! Dynamic language in all its splendor, for the good and for the bad... That can be done doesn't mean it's a good idea, Python lets you do almost everything, very good ideas and very bad ideas. When something is usually restricted is because it endangers the interpreter himself or for a very good reason of design, optimization, etc. Instead of doing this we have inheritance for example, but if we can even add methods to a class with created instances and above call them from the already created instances without any problem.So what exactly is a method in Python?If someone has a chance to read a little bit with the possibility of not understanding anything at the end because of me, it's good, but there it goes.In Python practically everything is an object in memory (including imported modules, the script itself, functions, classes, integers, etc), which in turn have methods, functions or anything with a method __call __()as objects that can be called.Attribute resolution (in which dict has a primary function) he does not care at all that the object is quiet or not. Just try to look for that name in the class or classes you derive from following the MRO. Then you try to call him, you try to assign him or fire him, but his mission ends when he gives you a reference to the attribute or an exception because he couldn't find it.In fact methods are objects that act as wrapping for functions by maintaining references to the instance to which they belong and thus linking the function with their instance. They are also created on the march by accessing the function as an attribute through the aforementioned syntax .nombre.If we look at how a method is defined, it does not differ in anything from defining a function, the only thing that changes is that a reference to class or to instance is received as a first argument (cls/self by convention no more).Obviously there has to be a mechanism that a function with class or instance and that allows reference to the method with .nombre. Python solves this using non-data descriptors. In the end we'll see him over.Note that Python is a dynamic language, in which a variable/attribute does not cease to be just an associated name at all times to a reference to an object in memory.This means that in the background all variables/attributes are the same, all are only paths to find an object in memory, no matter whether the object is quiet or not, or that at a given time the variable points to another object or that several points to it. The type and properties always belong to the object, not to the variable. Really for language doesn't matter if instancia.nombre is an integer, a string, a list or a method, all objects.In languages such as C++, this does not happen, data and methods are clearly separated, with data (attributes) fixed to a specific type and in which methods are not objects.The attribute dictThe attribute dict of an object (if it is also an attribute) behaves similarly to a dictionary, but it is not. It's really an instance of a class. DictProxy whose objects behave like dictionaries but with some differences, for example, we cannot add attributes how we do with the keys of a dictionary, this does not work: Clase.dict["foo"] = 13
We must use:Clase.foo = 13
orsetattr(Clase, "foo", 13)
For example, if we are so unconscious to do this:del instancia.dict
it is created again...Reasons to use DictProxy are several, in essence it is done by optimization, forcing the keys to always be chains, which allows interpreter to perform certain optimizations. Also for safety, to prevent things like the above from muting a class or instance and to send the interpreter himself to wind up...the "dictionaries" of classes as dict simply store methods as functions.The descriptorsA descriptor is an object that has at least one of the following magical methods in its attributes: get, set or delete. Its implementation and use is known as a descriptor protocol and that it is basically to change an attribute by an object (the descriptor) that intermediates in access to that attribute, thus allowing to define and establish the behavior of the attribute of an object.A descriptor that only implements get is called a non-data descriptor and are used to access methods as we will see. While if it implements more set they are data descriptors, which we are not very interested in this case.Descriptors are used for many things related to attributes and methods, they are everywhere on Python even if we don't see them. For example for static methods (@staticmethod), class methods (@classmethod) and properties (@property) are used descriptors, the decorators are nothing but a way to implement them in a simple way without appearing to be used.The properties are perhaps a very clear example of this:class Foo:
def init(self):
self._bar = None
@property
def bar(self):
return self._bar
@bar.setter
def bar(self, valor):
self._bar = valor
>>> inst = Foo()
>>> inst.bar = 5
>>> inst.bar
5
But all this goes a lot further, if I hadn't gotten into the descriptors' "charco." As I mentioned earlier, to allow a function to be called as methods need something else. Functions include the method get() to link the function with access to taxes .nombre, therefore all functions are non-data descriptors that return linked methods when invoked from an object.In fact, if we access a method through dictIt's not called getbut a reference to the function below is returned without more:class Foo:
def bar(self):
pass
>>> Foo.dict["bar"]
<function Foo.bar at 0x7f0345da3a60>
If we access using Clase.métodoif invoked get, since as discussed is the link between function and class to allow such syntax, but the underlying function object is also returned without further:>>> Foo.bar
<function Foo.bar at 0x7f0345da3a60>
In contrast, when accessed by the instance, the function is wrapped up in a linked method:>>> Foo().bar
<bound method Foo.bar of <main.Foo object at 0x7f0345df0460>>
This object internally stores the reference to the function and to the instance to which it is associated, inter alia:>>> Foo().bar.func
<function Foo.bar at 0x7f0345da3a60>
>>> Foo().bar.self
<main.Foo object at 0x7f0345df0460>
A method, therefore, is only an attribute linked to a function through a descriptor.