I'm unclear as to what this one paragraph in the python tutorial documentation is saying.
(found here: https://docs.python.org/3/tutorial/classes.html#method-objects)
When an instance attribute is referenced that isn’t a data attribute, its class is searched. If the name denotes a valid class attribute that is a function object, a method object is created by packing (pointers to) the instance object and the function object just found together in an abstract object: this is the method object. When the method object is called with an argument list, a new argument list is constructed from the instance object and the argument list, and the function object is called with this new argument list.
From my current understanding, I think what it's saying is that whenever you reference an attribute of an instance of a class like in the 8th line of this little snippet here:
class MyClass():
attribute = "I am an attribute"
def func(self):
return "I am a function"
instance = MyClass()
print(instance.func())
When python sees
instance.func()
what it's really doing isn't looking for a method func "owned by" instance, it's looking for a function func owned by MyClass, then calling that function owned by MyClass with instance as the self parameter.
so basically it's the same thing as:
MyClass.func(instance)
I feel like I'm missing something subtle though. I don't understand what it means by
... a method object is created by packing (pointers to) the instance object and the function object just found together in an abstract object: this is the method object.
What is an abstract object?
What does it mean to "pack" a pointer?
What does it mean to "pack" multiple pointers?
Why even have a method object for instance if python is just going to look at MyClass's function object?
Why doesn't python just make methods be "owned by" their instances? Why even go through the whole process of calling MyClass's func instead of instance's func?
Why did the designers of the language decide to make it be this way?
"Abstract object" means that there isn't necessarily a real Python object being created, it's just a way of describing what's happening behind the scenes as if there were some object being created.
"packing" means that it's just collecting these things together into this abstract object.
So when you write
instance.func()
it internally creates something that represents the function combined with the instance. When this is called, the method function is called as you described, with the instance passed as the first argument (conventionally named self).
Why do this? So that you can pass these things around:
foo = instance.func
foo()
The value of foo contains that abstract object that represents the function combined with the instance.
Methods are owned by classes so that all instances of a class automatically get the same method. This is the essence of OO programming and the basis of inheritance among classes.
Related
Lately, I've been studying Python's class instantiation process to really understand what happen under the hood when creating a class instance. But, while playing around with test code, I came across something I don't understand.
Consider this dummy class
class Foo():
def test(self):
print("I'm using test()")
Normally, if I wanted to use Foo.test instance method, I would go and create an instance of Foo and call it explicitly like so,
foo_inst = Foo()
foo_inst.test()
>>>> I'm using test()
But, I found that calling it that way ends up with the same result,
Foo.test(Foo)
>>>> I'm using test()
Here I don't actually create an instance, but I'm still accessing Foo's instance method. Why and how is this working in the context of Python ? I mean self normally refers to the current instance of the class, but I'm not technically creating a class instance in this case.
print(Foo()) #This is a Foo object
>>>><__main__.Foo object at ...>
print(Foo) #This is not
>>>> <class '__main__.Foo'>
Props to everyone that led me there in the comments section.
The answer to this question rely on two fundamentals of Python:
Duck-typing
Everything is an object
Indeed, even if self is Python's idiom to reference the current class instance, you technically can pass whatever object you want because of how Python handle typing.
Now, the other confusion that brought me here is that I wasn't creating an object in my second example. But, the thing is, Foo is already an object internally.
This can be tested empirically like so,
print(type(Foo))
<class 'type'>
So, we now know that Foo is an instance of class type and therefore can be passed as self even though it is not an instance of itself.
Basically, if I were to manipulate self as if it was a Foo object in my test method, I would have problem when calling it like my second example.
A few notes on your question (and answer). First, everything is, really an object. Even a class is an object, so, there is the class of the class (called metaclass) which is type in this case.
Second, more relevant to your case. Methods are, more or less, class, not instance attributes. In python, when you have an object obj, instance of Class, and you access obj.x, python first looks into obj, and then into Class. That's what happens when you access a method from an instance, they are just special class attributes, so they can be access from both instance and class. And, since you are not using any instance attributes of the self that should be passed to test(self) function, the object that is passed is irrelevant.
To understand that in depth, you should read about, descriptor protocol, if you are not familiar with it. It explains a lot about how things work in python. It allows python classes and objects to be essentially dictionaries, with some special attributes (very similar to javascript objects and methods)
Regarding the class instantiation, see about __new__ and metaclasses.
I did not understand the following sentence from Python tutorial:
there are no shorthands for referencing the object's members from it's methods.The method function is declared with an explicit 1st argument representing the object, which is provided implicitly by the call.
Does this mean, in every method of a class, its object is hidden along with the data members? Can this be explained with sample code?
This is just referring to the fact that in an object's methods, the object itself is always the first argument (i.e., the "self" in def method(self, arg1, arg2)), and that you need to explicitly say that you want self.var in the method rather than just saying var.
For more background on why that decision was made, see https://docs.python.org/2/faq/design.html#why-must-self-be-used-explicitly-in-method-definitions-and-calls from the docs or http://neopythonic.blogspot.com.au/2008/10/why-explicit-self-has-to-stay.html for some examples.
New to Python, trying to understand exactly what the self in the __init_(self) function is referring to.
A few tutorials I'm working with describe self as
referring to the instance whose method was called.
Which is not exactly a trivial statement for someone new to OOP.
I've been reading a lot about the whole backstory as to why you have to actually include an explicit self in Python, but need a simple explanation as to what it means to say that self is used to refer to the instance object ——> Does that mean that self is actually referring to the object that is the class itself you've just created? In other words, self somehow "boots up" the class in memory as an object?
Your second-last sentence is correct, but the last sentence is not. It has nothing to do with "booting up" or creating the object at all - the object already exists by that point.
I think you are missing the fact that self is used in all methods, not just __init__, to refer to the specific object that the method belongs to.
For instance, if you had a simple object with a name property, and a method called print_name, it might look like this:
def print_name(self):
print(self.name)
So here the method is using self to refer to the properties of the object it has been called on.
When objects are instantiated, the object itself is passed into the self parameter.
Because of this, the object’s data is bound to the object. Below is an example of how you might like to visualize what each object’s data might look. Notice how ‘self’ is replaced with the objects name. I'm not saying this example diagram below is wholly accurate but it hopefully with serve a purpose in visualizing the use of self.
EDIT (due to further question: Could you explain why exactly when objects are instantiated, the object itself is passed into the self parameter?)
The Object is passed into the self parameter so that the object can keep hold of its own data.
Although this may not be wholly accurate, think of the process of instantiating an object like this: When an object is made it uses the class as a template for its own data and methods. Without passing it's own name into the self parameter, the attributes and methods in the class would remain as a general template and would not be referenced to (belong to) the object. So by passing the object's name into the self parameter it means that if 100 objects are instantiated from the one class, they can all keep track of their own data and methods.
See the illustration below:
Every member function of a class, including the constructor (__init__) is invoked for a certain instance (object) of that class. Member functions have to be able to access the object for which they are called.
So e.g. in a.f(), f() has to have acces to a. In f, defined as f (this), this refers to a.
The special thing for a constructor is that there is no object "before the dot" yet, because precisely that object is being constructed. So this refers to the object "just being constructed" in that case.
When you write myClass(), python first creates an instance of your class, then immediately calls __init__() passing this object as the argument. self is a defined object in memory by the time you call __init__().
Behind the scenes, object construction is actually quite complicated.
Classes are objects too, and the type of a class is type (or a subclass, if using metaclasses). type has a __call__ method that is responsible for constructing instances. It works something like:
class type:
def __call__(cls, *args, **kwargs):
self = cls.__new__(cls, *args, **kwargs)
if isinstance(self, cls):
cls.__init__(self, *args, **kwargs)
Note, the above is for demonstrative purposes only.
Remember that, if a function is not defined on a class itself, it is looked up on its parent (as controlled by the mro), and usually.
Ultimately, __new__ must either call object.__new__(cls) to allocate a new instance of a class cls, or else return an existing object. If the existing object is of a different class, __init__ will not be called. Note that if it returns an existing object of the right class (or a subclass), __init__ will be called more than once. For such classes, all of the work is usually done in __new__.
Chances are you'll never use any of this, but it might help you understand what's going on behind the scenes.
Simply, it means you are referring to a method or variable that is local to the object.
You can look at 'self' as referrer or a pointer to class internals which with that you can invoke methods or add/remove/update/delete attributes . Class is somehow an isolated object which has its own representation of data given to it . So basically , self is only explicitly defined as an argument, which with using that you can get access to class internals . Some programming languages does not explicitly include the keyword self. or some uses this ( like C ++ ) . take a look here:
a = 1
b = 2
class test(object):
def __init__(self,a,b):
self.a = a + 1
self.b = b + 1
def show_internals(self):
print self.a, '\t', self.b
def change_internals(self,a,b):
self.a = a
self.b = b
_my_class = test(3,4)
print a , b
_my_class.show_internals()
_my_class.change_internals(5,6)
_my_class.show_internals()
print a , b
the result is :
1 2
4 5
5 6
1 2
As you can see, with using self you can manipulate the data within the object itself. Otherwise you would end up editing global variables.
Say I have this code:
class ClassStyleA(object):
def FunctionA(self):
print "This is Style A."
class ClassStyleB(object):
def FunctionA(self):
print "This is Style B."
class InstanceStyleA(ClassStyleA):
def FunctionB(self):
print "This is also Style A."
InstanceStyleB = ClassStyleB()
If I want to call, for example, FunctionA, from InstanceStyleA, I need to type it like this:
InstanceStyleA().FunctionA()
If I want to call FunctionA from InstanceStyleB, I need to type it like this:
InstanceStyleB.FunctionA()
I need to add a set of parentheses after InstanceStyleA in order to call one of its functions, otherwise I get this error:
TypeError: unbound method FunctionA() must be called with InstanceStyleA instance as first argument (got nothing instead)
Similarly, if I try to add the parentheses after InstanceStyleB when calling one of it's functions, I get this error:
TypeError: 'ClassStyleB' object is not callable
Why is this the case? Why are they treated differently if they are both instances of a class?
In your example code, you actually have three classes and one object, all confusingly named:
ClassStyleA is a class, that inherits from object
ClassStyleB is also a class that inherits from object
InstanceStyleA is not an instance, it is also a class, that inherits from ClassStyleA.
InstanceStyleB is not a class, it's an instance of the class ClassStyleB
To create an instance from a class, you call the class. So, ClassStyleA(), ClassStyleB(), InstanceStyleA() are all instances. So is InstanceStyleB - it's a variable to which you assign the instance created with ClassStyleB.
Since InstanceStyleB (without parentheses) is already an instance (of ClassStyleB), and not a class, you can't call it. This explains your second TypeError.
Analogously, you can only call methods (functions defined in a class, in your example it's FunctionA and FunctionB) on an instance. This explains your first TypeError: InstanceStyleA (again, without parentheses), is a class.
(Pedantic aside: much of above is, technically speaking, utter lies, but for the sake of this discussion it's simpler to pretend Python has a clear separation between classes and instances, and functions and methods.)
When you call InstanceStyleA with parenthesis, you are creating an instance of InstanceStyleA... and then calling the member function on that instance. It is basically shorthand for:
obj = InstanceStyleA()
obj.FunctionA()
InstanceStyleB is not a class, it is set to an instance of ClassStyleB, so when you are referencing it, there is no need for parenthesis (or instantiating an object).
it would be the same as if you wrote:
ClassObject = ClassStyleB()
ClassObject.FunctionA()
The TypeError is because objects aren't callable. For instance:
d = {} #d is a dictionary
d() #d used as a function has no meaning
I hope this clears up the difference.
Could somebody please elaborate this paragraph to me:
If you still don’t understand how methods work, a look at the
implementation can perhaps clarify matters. When an instance attribute
is referenced that isn’t a data attribute, its class is searched. If
the name denotes a valid class attribute that is a function object, a
method object is created by packing (pointers to) the instance object
and the function object just found together in an abstract object:
this is the method object. When the method object is called with an
argument list, a new argument list is constructed from the instance
object and the argument list, and the function object is called with
this new argument list.
Especially the part:
If the name denotes a valid class attribute that is a function object,
a method object is created by packing (pointers to) the instance
object and the function object just found together in an abstract
object: this is the method object.
Difference between Method Object and Function Object?
Thanks.
A method object is a wrapper for a function object that allows the function to be attached (bound) to an instance. The method object knows what instance it is bound to, and, when it is called, it calls the wrapped function, passing the instance as the first argument. In other words, the method object is responsible for the explicit passing of self that is characteristic of Python.