python method as argument - python

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).

Related

Calling a method of a class before creating an object

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.

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..:)

Python - function as class attribute becomes a bound method

I noticed that if I define a class attribute equal to a function when I create an instance of that class the attribute becomes a bound method. Can someone explain me the reason of this behaviour?
In [9]: def func():
...: pass
...:
In [10]: class A(object):
....: f = func
....:
In [11]: a = A()
In [12]: a.f
Out[12]: <bound method A.func of <__main__.A object at 0x104add190>>
In [13]: a.f()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-13-19134f1ad9a8> in <module>()
----> 1 a.f()
global a.f = <bound method A.func of <__main__.A object at 0x104add190>>
TypeError: func() takes no arguments (1 given)
You assigned a function to the attribute A.f (the attribute f of the class A). The attribute A.f was defined as part of the class. It is a function, so it is by default an instance method of that class.
Creating an instance (named a) of class A causes that instance to have an attribute f, and you access that by the name a.f. This is a bound method (cause it's bounded to the object a; further explanation here).
Every instance method, when it is called, automatically receives the instance as its first argument (conventionally named self). Other types of method are possible: - see class methods and static methods.
For this reason the error says that func takes no arguments (as it's defined as def func():) but received 1 (self).
To do what you want, you should tell python that you're using a static method
def func():
pass
class A(object):
f = staticmethod(func)
Python is not a message based OO system1. Instead, similar to JavaScript, properties are resolved to first-class functions and then invoked; the behavior differs a bit in the mechanics of such, as discovered.
In Python the requirement is that methods have at least one parameter, normally called self, that will be automatically supplied the associated instance when it is invoked as a method.
Furthermore (and perhaps to the point of the question), Python does not differentiate between using def f.. or f = some_func() when establishing instance member bindings; arguably this matches behavior outside of classes.
In the example, assigning the function to the instance 'makes it expect to be treated like an instance method'. It is the exact same - parameterless - function called in both cases; only the future usage of such is relevant.
Now, unlike JavaScript, Python handles methods and object association through the concept of bound methods - functions resolved as methods are always 'bound'.
The behavior of a.f returning a bound method - function that will automatically supply the bound object to the first parameter as self - is done independently of the source of the function. In this case that means the parameterless function cannot be used when it is 'bound' as it does not accept a self parameter.
As a demonstration, the following will fail in the same way because the source underlying method does not meet the minimum requirements of accepting the instance as an argument:
g = a.f
g()
In this case calling g() is equivalent to calling func(a).
1 For comparison, Java, C#, Ruby, and SmallTalk are message based OO systems - in these an object is told to invoke a method by a 'name', instead of resolving a method (or function) as a value which can be invoked.
A little late to the party, but another viable solution is in storing the function as dictionary, which is an attribute of the class.
# Some arbitrary function
def f(x):
return x
# A class, which will wrap the function as a dictionary object, which is a class attr
class Test:
def __init__(self,f):
self.f = {'f':f}
def func(self,x):
return self.f['f'](x)
# Now let's test the Test object
t = Test(f=f)
t.func(3)
>>>
3
This approach is more verbose than the accepted answer, however, it doesn't get into staticmethod, decorators, or other advanced topics. So, this will work in a pinch if you're intimidated by the other, preferred approach.
Edit: If you want this to robust enough to handle keyword arguments:
class Test:
def __init__(self,f):
self.f = {'f':f}
def func(self,p):
return self.f['f'](**p)
def f(**p):
return p['x'] * p['y']
t = Test(f=f)
t.func({'x':2,'y':3})
>>>
6

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)

How does assignment of a function as a class attribute become a method in Python?

>>> class A(object): pass
>>> def func(cls): pass
>>> A.func = func
>>> A.func
<unbound method A.func>
How does this assignment create a method? It seems unintuitive that assignment does the following for classes:
Turn functions into unbound instance methods
Turn functions wrapped in classmethod() into class methods (actually, this is pretty intuitive)
Turn functions wrapped in staticmethod() into functions
It seems that for the first, there should be an instancemethod(), and for the last one, there shouldn't be a wrapper function at all. I understand that these are for uses within a class block, but why should they apply outside of it?
But more importantly, how exactly does assignment of the function into a class work? What magic happens that resolves those 3 things?
Even more confusing with this:
>>> A.func
<unbound method A.func>
>>> A.__dict__['func']
<function func at 0x...>
But I think this is something to do with descriptors, when retrieving attributes. I don't think it has much to do with the setting of attributes here.
You're right that this has something to do with descriptor protocol. Descriptors are how passing the receiver object as the first parameter of a method is implemented in Python. You can read more detail about Python attribute lookup from here. The following shows on a bit lower level, what is happening when you do A.func = func; A.func:
# A.func = func
A.__dict__['func'] = func # This just sets the attribute
# A.func
# The __getattribute__ method of a type object calls the __get__ method with
# None as the first parameter and the type as the second.
A.__dict__['func'].__get__(None, A) # The __get__ method of a function object
# returns an unbound method object if the
# first parameter is None.
a = A()
# a.func()
# The __getattribute__ method of object finds an attribute on the type object
# and calls the __get__ method of it with the instance as its first parameter.
a.__class__.__dict__['func'].__get__(a, a.__class__)
# This returns a bound method object that is actually just a proxy for
# inserting the object as the first parameter to the function call.
So it's the looking up of the function on a class or an instance that turns it into a method, not assigning it to a class attribute.
classmethod and staticmethod are just slightly different descriptors, classmethod returning a bound method object bound to a type object and staticmethod just returns the original function.
Descriptors are the magic1 that turns an ordinary function into a bound or unbound method when you retrieve it from an instance or class, since they’re all just functions that need different binding strategies. The classmethod and staticmethod decorators implement other binding strategies, and staticmethod actually just returns the raw function, which is the same behavior you get from a non-function callable object.
See “User-defined methods” for some gory details, but note this:
Also notice that this transformation only happens for user-defined functions; other callable objects (and all non-callable objects) are retrieved without transformation.
So if you wanted this transformation for your own callable object, you could just wrap it in a function, but you could also write a descriptor to implement your own binding strategy.
Here’s the staticmethod decorator in action, returning the underlying function when it’s accessed.
>>> #staticmethod
... def f(): pass
>>> class A(object): pass
>>> A.f = f
>>> A.f
<function f at 0x100479398>
>>> f
<staticmethod object at 0x100492750>
Whereas a normal object with a __call__ method doesn’t get transformed:
>>> class C(object):
... def __call__(self): pass
>>> c = C()
>>> A.c = c
>>> A.c
<__main__.C object at 0x10048b890>
>>> c
<__main__.C object at 0x10048b890>
1 The specific function is func_descr_get in Objects/funcobject.c.
What you have to consider is that in Python everything is an object. By establishing that it is easier to understand what is happening. If you have a function def foo(bar): print bar, you can do spam = foo and call spam(1), getting of course, 1.
Objects in Python keep their instance attributes in a dictionary called __dict__ with a "pointer" to other objects. As functions in Python are objects as well, they can be assigned and manipulated as simple variables, passed around to other functions, etc. Python's implementation of object orientation takes advantage of this, and treats methods as attributes, as functions that are in the __dict__ of the object.
Instance methods' first parameter is always the instance object itself, generally called self (but this could be called this or banana). When a method is called directly on the class, it is unbound to any instance, so you have to give it an instance object as the first parameter (A.func(A())). When you call a bound function (A().func()), the first parameter of the method, self, is implicit, but behind the curtains Python does exactly the same as calling directly on the unbound function and passing the instance object as the first parameter.
If this is understood, the fact that assigning A.func = func (which behind the curtains is doing A.__dict__["func"] = func) leaves you with an unbound method, is unsurprising.
In your example the cls in def func(cls): pass actually what will be passed on is the instance (self) of type A. When you apply the classmethod or staticmethod decorators do nothing more than take the first argument obtained during the call of the function/method, and transform it into something else, before calling the function.
classmethod takes the first argument, gets the class object of the instance, and passes that as the first argument to the function call, while staticmethod simply discards the first parameter and calls the function without it.
Point 1: The function func you defined exists as a First-Class Object in Python.
Point 2: Classes in Python store their attributes in their __dict__.
So what happens when you pass a function as the value of a class attribute in Python? That function is stored in the class' __dict__, making it a method of that class accessed by calling the attribute name you assigned it to.
Relating to MTsoul's comment to Gabriel Hurley's answer:
What is different is that func has a __call__() method, making it "callable", i.e. you can apply the () operator to it. Check out the Python docs (search for __call__ on that page).

Categories

Resources