Calling a method of a class before creating an object - python

Let's say we have a class, and we are calling it's method before creating an object:
class ParentClass:
def MyMethod(self):
self.a=5
print("I am Method")
ParentClass.MyMethod(ParentClass)
Why do we get a result?
Also, why hasattr(ParentClass,'a') is showing that instance variable is created?

You get a result because you ParentClass.MyMethod evaluates to a regular function that takes one argument, which you supplied. The function doesn't care what the type of self is, as long as you can define an attribute named a for it. The result of ParentClass.MyMethod(ParentClass) is to add an attribute named a to ParentClass.
ParentClass().MyMethod, on the other hand, produces an instance of method that wraps the function, due to the descriptor protocol. The method, when called, simply calls the function with the instance as the first argument and the rest of its own arguments. Because the function doesn't expect any more arguments, you would get a TypeError.

Related

Are all methods are preceded by a dot(.) or just some of them. How do we define it needs a dot or not?

I was learning Python by using Python Crash Course and came upon this String and Method thing: It only said that the dot(.) after name in name.title() tells Python to make the title() method act on the variable name.
Not always, you can create a method dynamically:
from types import MethodType
def fn(x):
return x.var
class A:
def __init__(self):
self.var = 20
obj = A()
method_ = MethodType(fn, obj)
print(method_)
print(method_())
output :
<bound method fn of <__main__.A object at 0x000001C5E3F01FD0>>
20
A method is an instance of type MethodType and also it has an object bound to it, when method gets called, it's first parameter will always get filled with that object. Here fn() function's first parameter (x) will be filled with obj object.
The above answer is precise but i wanted to add to it.
Actually methods are functions that take objects as arguments and then return values based on that and as python is an Object Oriented Language therefore everything in python is an object.
When you call name.title():
then, python search for the title() method for the name object.And as all methods are designated to take the object as an argument:
`def title(self):
...+
`
This is what a method definition look like inside a class and the self argument here stands for the object calling the method.
And we do not have to specify it explicitly it is recognised by the python interpreter.
As in your case: name.title() the object calling the method title() is the name variable therefore here self is assigned the value of name that is the function call name.title() is equivalent to title(name) but the former is the correct syntax of calling the method whereas the latter one is for comprehesion purpose.
If you run title(name) it surely gonna raise an error.
But, as the title() method belongs to the str class you can always call str.title(name).
Hope i didn't confuse you instead of making it clearer...Happy coding..:)

Passing self object to function that requires this type

I wanted to write a class function which takes Signal object as a parameter and returns its copy. Then I wanted to overload this function with an instance function that returns copy of self argument. I have a following code:
#classmethod
def copy(cls, arg):
if not isinstance(arg, Signal):
raise ValueError("Argument must be of type Signal")
result = Signal()
result.framerate = arg.framerate
return result
def copy(self):
return FragmentsSignal.copy(self)
and
Signal1 = Signal(100)
Signal2 = signal1.copy()
But after calling the function copy my code goes into infinite recursive loop and throws name of this site as an exception. My questions are:
Do I properly use python function overloading mechanism?
How can I pass *this argument to a class function within my class?
Do I properly use python function overloading mechanism?
You can't have two functions with the same name; Python does not support overloading based on the types of the arguments. The definition of the second function will override that of the first.
In essence you're calling the non classmethod function copy over and over again. You'll need to rename one of these in order to get it to work effectively.
How can I pass *this argument to a class function within my class?
I'm guessing you mean self here; passing self to another function is done as with any other arg (as you did FragmentsSignal.copy(self)). Your issue is that you're getting stumped by the recursion caused by the similar names.

Different ways of calling class functions

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.

python method as argument

So I know in python everything is an 'object' meaning that it can be passed as an argument to a method. But I'm trying to understand how exactly does this work. So I was trying out the following example:
class A:
def __init__(self):
self.value = 'a'
def my_method(self)
print self.value
class B:
def __init__(self):
self.values = 'b'
def my_method(self, method):
method()
a = A()
b = B()
b.my_method(a.my_method)
Now first this was written just to see how things work. I know I should for example check if my_method 's argument is callable. Now my question is:
How exactly is the method passed here? I mean the output I'm recieving is 'a' so I'm guessing that when a object method is passed as parameter so is the actual object ? In this case when I pass a.my_method the instance a is also passed ?
When you access a.my_method Python sees that it is an attribute of the class and that A.my_method has a method __get__() so it calls A.my_method.__get__(a), that method creates a new object (the 'bound method') which contains both a reference to A.my_method and a reference to a itself. When you call the bound method it passes the call back through to the underlying method.
This happens every time you call any method whether you call it directly or, as in your code, delay the actual call until later. You can find more description of the descriptor protocol as it is known at http://docs.python.org/reference/datamodel.html#descriptors
How exactly is the method passed here?
This is easily answered: in Python, everything is an object :) Also functions/methods, which are specific function objects which can be passed as parameters.
In this case when I pass a.my_method the instance a is also passed?
Yes, in this case the instance a is also passed, though embedded in the function object and cannot be retrieved. On the contrary you could pass the function itself and supply it with an instance. Consider the following example:
b = B()
func = A.my_method # Attention, UPPERCASE A
func(b)
This would call the A classes method my_method with an instance of B.
Functions are 'first-class objects' in Python. What that means is that a function is an object as much as a list or an integer. When you define a function, you are actually binding the function object to the name you use in the def.
Functions can be bound to other names or passed as parameters to functions (or stored in lists, or...).
source: http://mail.python.org/pipermail/tutor/2005-October/042616.html
a.my_method returns not exactly the function you defined in the class A (you can get it via A.my_method) but an object called a 'bound method' which contains both the original function (or 'unbound method' in Python 2, IIRC) and the object from which it was retrieved (the self argument).

python and using 'self' in methods

From what I read/understand, the 'self' parameter is similiar to 'this'.
Is that true?
If its optional, what would you do if self wasnt' passed into the method?
Yes, it's used in similar ways. Note that it's a positional parameter and you can call it what you want; however there is a strong convention to call it self (not this or anything else). Some positional parameter must be there for a usable instance method; it is not optional.
The joy of Python
That is true to some extend. Methods are bound to the object instance they are a part of. When you see
def some_func(self, foo, bar)
The passing of self is sometimes implicit when you call, for example:
obj.some_func(foo_val, bar_val)
Which is equal (presuming obj is of class MyClass) to
MyClass.some_func(obj, foo_val, bar_val)
Because the method is bound to obj, the self argument gets populated. This is part of Python being explicit with what it means. In other languages, this just pops into scope, with Python there is some exposure of how this happens.
You can also pass methods around, and manually pass them self when not calling from a bound context.
The Python docs do a good Job:
xf = x.f
while True:
print xf()
will continue to print hello world until the end of time.
What exactly happens when a method is called? You may have noticed that x.f() was called >without an argument above, even though the function definition for f() specified an >argument. What happened to the argument? Surely Python raises an exception when a function >that requires an argument is called without any — even if the argument isn’t actually >used...
Actually, you may have guessed the answer: the special thing about methods is that the >object is passed as the first argument of the function. In our example, the call x.f() is >exactly equivalent to MyClass.f(x). In general, calling a method with a list of n arguments >is equivalent to calling the corresponding function with an argument list that is created >by inserting the method’s object before the first argument.
self is this, just you have to explicitly pass it and explicitly use it to refer to class methods/properties.
It isn't optional in class methods. You will get a TypeError if you try to define a classmethod without at least one argument (i.e., the self parameter).
However, you can call it something other than self, but I have never seen otherwise.
self refers to the object on which the method was called, much like this in C++. But it is important that self is merely a convention, you can name it as you like and pass instances of subclasses.
In classes a self variable (or cls for classmethods) is required. What you want to call it is your decision though. If you prefer you could call it this instead.
A classmethod is a method that gets the class as a first argument instead of a instance. It can be called without passing an instance.
i.e. with a classmethod you can do:
SomeObject.some_class_method()
while a normal method would require you to do
SomeObject().some_normal_method()
or
SomeObject.some_normal_method(instance)
self is definitely similar to this, however, in Python, the name self is just a convention, and could be named anything else. The variable is named after whatever you call it in the function's prototype (def function(whatever, params...):).
For instance methods, self IS actually required. For class or static methods, you need to specify that they should be treated as such, and then self is not required. For example:
def type_to_display(type):
"""Converts a pass type to the full written pass type."""
return list((pair[1] for pair in Pass.TYPE_CHOICES if pair[0] ==
type[0:1].upper()))[0]
type_to_display = staticmethod(type_to_display)
You will never be able to use an instance method in such a way that self is not passed in. For example, if I have an instance my_car of a Car class, and I use the Car class's drive instance method, the my_car instance will be implicitly passed into the drive method as the first parameter (self).
class Car:
def drive(self):
self.do_some_stuff()
my_car = Car()
my_car.drive() # actually calls Car.drive(my_car)

Categories

Resources