What are functions outside of a class called? - python

I failed to phrase the question correctly online so I could not get an answer.
We have instance methods, static methods, and class methods.
What are functions called when they don't belong to a class?

They're just called functions.
In python, "function" refers to a type of callable procedure/block of code with its own localized namespace.
In contrast, "method" refers specifically to a kind of function that is bound to a class. We use "instance methods", "static methods", and "class methods" to differentiate between how those functions are bound to their respective classes, but in any case we call them methods because they are bound to their class.
So, we just call them functions, unless we have something more specific. If you must use some sort of qualifier, "unbound function" (alluding to the fact that it's not bound to any class) or "module function" (alluding to the fact that it's bound to the module it's defined in, though that's not a class), or even "static function" (but this could be confusing when trying to communicate to people who don't know the difference between functions and methods) or "free function" will probably work.

According to the section "Callable types" in the Python docs on its Data model
A user-defined function object is created by a function definition
So I guess one could say that everything that begins with def is a function.
In general, I think it depends a lot on the context, which term you want to use. For example, even though, to define a "static method", you'd write #staticmethod and everything, it's not called a "method" but a "function" in the context of the types module:
>>> class A:
... def f(self):
... print("Hello from method `f`")
... #staticmethod
... def g():
... print("Hello from function `g`")
...
>>> a = A()
>>> a.f()
Hello from method `f`
>>> a.g()
Hello from function `g`
>>> type(a.f)
<class 'method'>
>>> type(a.g)
<class 'function'>
Furthermore, looking at the docs of Python's types module reveals:
types.MethodType - The type of methods of user-defined class instances.
So methods are only found in instances. A method b.f of an instance b of a class B refers to the function B.f of the class:
>>> class B:
... def f(self):
... pass
...
>>> b1 = B()
>>> type(b1.f)
<class 'method'>
>>> type(B.f)
<class 'function'>
The methods are different objects for each instance:
>>> b2 = B()
>>> b1.f is b2.f
False
However, the methods refer to the same function B.f:
>>> b1.f.__func__
<function B.f at 0x7f166e31b2f0>
>>> b1.f.__func__ is b2.f.__func__
True
I imagine, this can be both useful or a pitfall, so it makes sense to know about it.
Here is an example, using a class C with function C.f and cache, an argument with a mutable default value:
>>> class C:
... def f(self, cache=[]):
... cache.append(cache[-1] + 1 if cache else 1)
... print(cache)
...
>>> c1 = C()
>>> c2 = C()
>>> c1.f()
[1]
>>> c2.f()
[1, 2]
>>> c3 = C()
>>> c3.f()
[1, 2, 3]
As you can see, all instances c1, c2 and c3 of class C share the same underlying function C.f with its argument cache.

Related

Why does 'is' not work when comparing instance methods in python [duplicate]

This question already has answers here:
Why don't methods have reference equality?
(2 answers)
Closed 7 years ago.
I've noticed that sometimes instance methods do not compare as identical (using is rather than ==), even when they relate to the same bound instance method e.g.
>>> class A(object):
... def f(self):
... print "hi"
...
>>> a = A()
>>> f1 = a.f
>>> f2 = a.f
>>> f1 is f2
False
>>> f1 == f2
True
I've ended up using == to check to see if two variables refer to the same bound method, but I was wondering if anyone knew why is does not behave as I would expect?
methods are implemented as descriptors -- So each time you access the f member, a new function is created. You can see this by looking at their ids...
>>> class A(object):
... def f(self):
... pass
...
>>> a = A()
>>> f1 = a.f
>>> f2 = a.f
>>> id(f1)
4325305232
>>> id(f2)
4325818528
To be a little more clear what I mean when I say that they are implemented via descriptors, the following expressions:
a = A()
func = a.f
are equivalent to:
a = A()
func = A.f.__get__(a, A)
Clearly you don't want to be writing the latter all the time, so the shortcut is pretty nice :-).
With that said, this starts to explain how a bound method knows what self is since a (which is self in the method) gets passed to __get__ which is what constructs the bound method.

Apply a method to an object of another class

Given two non-related classes A and B, how to call A.method with an object of B as self?
class A:
def __init__(self, x):
self.x = x
def print_x(self):
print self.x
class B:
def __init__(self, x):
self.x = x
a = A('spam')
b = B('eggs')
a.print_x() #<-- spam
<magic>(A.print_x, b) #<-- 'eggs'
In Python 3.x you can simply do what you want:
A.print_x(b) #<-- 'eggs'
If you only have an instance of 'A', then get the class first:
a.__class__.print_x(b) #<-- 'eggs'
In Python 2.x (which the OP uses) this doesn't work, as noted by the OP and explained by Amber in the comments:
This is a difference between Python 2.x and Python 3.x - methods in
3.x don't enforce being passed the same class.
More details (OP edit)
In python 2, A.print_x returns an "unbound method", which cannot be directly applied to other classes' objects:
When an unbound user-defined method object is called, the underlying function (im_func) is called, with the restriction that the first argument must be an instance of the proper class (im_class) or of a derived class thereof. >> http://docs.python.org/reference/datamodel.html
To work around this restriction, we first have to obtain a "raw" function from a method, via im_func or __func__ (2.6+), which then can be called passing an object. This works on both classes and instances:
# python 2.5-
A.print_x.im_func(b)
a.print_x.im_func(b)
# python 2.6+
A.print_x.__func__(b)
a.print_x.__func__(b)
In python 3 there's no such thing anymore as unbound method.
Unbound methods are gone for good. ClassObject.method returns an
ordinary function object, instance.method still returns a bound
method object. >> http://www.python.org/getit/releases/3.0/NEWS.txt
Hence, in python 3, A.print_x is just a function, and can be called right away and a.print_x still has to be unbounded:
# python 3.0+
A.print_x(b)
a.print_x.__func__(b)
You don't (well, it's not that you can't throw enough magic at it to make it work, it's that you just shouldn't). If the function is supposed to work with more than one type, make it... a function.
# behold, the magic and power of duck typing
def fun(obj):
print obj.x
class A:
x = 42
class B:
x = 69
fun(A())
fun(B())
I don't know why you would really want to do this, but it is possible:
>>> class A(object):
... def foo(self):
... print self.a
...
>>> class B(object):
... def __init__(self):
... self.a = "b"
...
>>> x = A()
>>> y = B()
>>> x.foo.im_func(y)
b
>>> A.foo.im_func(y)
b
An instance method (a class instance's bound method) has a property called im_func which refers to the actual function called by the instance method, without the instance/class binding. The class object's version of the method also has this property.

What is the difference between class and data attributes?

To quote diveintopython,
"You already know about data attributes, which are variables owned by
a specific instance of a class. Python also supports class attributes,
which are variables owned by the class itself."
In what sense are class attributes owned by a class? If you change the value of a class attribute in a specific instance, that change is only reflected in that instance (and not in other instances of the class).
From my vantage point this makes class attributes fundamentally the same as data (i.e. instance) attributes (notwithstanding the syntactic differences).
In C++ change the value of a "class variable", and that change is reflected in all instances.
What is the difference between the two?
I think that this example will explain the meaning to you.
class A(object):
bar = 1
a = A()
b = A()
b.bar = 2
print a.bar # outputs 1
A.bar = 3
print a.bar # outputs 3
print b.bar # outputs 2
In this case b.bar will be owned by instance after b.bar = 2 but a.bar will still be owned by class. That is why it will be changed on instance after changing it on class and b.bar will not.
This question is a duplicate of this one:
>>> class B(object):
... foo = 1
...
>>> b = B()
>>> b.__dict__
{}
>>> b.foo = 2
>>> b.__dict__
{'foo': 2}
When you assign a value to b, you add an instance variable; you're not modifying the class attribute.

Convert partial function to method in python

Consider the following (broken) code:
import functools
class Foo(object):
def __init__(self):
def f(a,self,b):
print a+b
self.g = functools.partial(f,1)
x=Foo()
x.g(2)
What I want to do is take the function f and partially apply it, resulting in a function g(self,b). I would like to use this function as a method, however this does not currently work and instead I get the error
Traceback (most recent call last):
File "test.py", line 8, in <module>
x.g(2)
TypeError: f() takes exactly 3 arguments (2 given)
Doing x.g(x,2) however works, so it seem the issue is that g is considered a "normal" function instead of a method of the class. Is there a way to get x.g to behave like a method (i.e implicitly pass the self parameter) instead of a function?
There are two issues at hand here. First, for a function to be turned into a method it must be stored on the class, not the instance. A demonstration:
class Foo(object):
def a(*args):
print 'a', args
def b(*args):
print 'b', args
Foo.b = b
x = Foo()
def c(*args):
print 'c', args
x.c = c
So a is a function defined in the class definition, b is a function assigned to the class afterwards, and c is a function assigned to the instance. Take a look at what happens when we call them:
>>> x.a('a will have "self"')
a (<__main__.Foo object at 0x100425ed0>, 'a will have "self"')
>>> x.b('as will b')
b (<__main__.Foo object at 0x100425ed0>, 'as will b')
>>> x.c('c will only recieve this string')
c ('c will only recieve this string',)
As you can see there is little difference between a function defined along with the class, and one assigned to it later. I believe there is actually no difference as long as there is no metaclass involved, but that is for another time.
The second problem comes from how a function is actually turned into a method in the first place; the function type implements the descriptor protocol. (See the docs for details.) In a nutshell, the function type has a special __get__ method which is called when you perform an attribute lookup on the class itself. Instead of you getting the function object, the __get__ method of that function object is called, and that returns a bound method object (which is what supplies the self argument).
Why is this a problem? Because the functools.partial object is not a descriptor!
>>> import functools
>>> def f(*args):
... print 'f', args
...
>>> g = functools.partial(f, 1, 2, 3)
>>> g
<functools.partial object at 0x10042f2b8>
>>> g.__get__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'functools.partial' object has no attribute '__get__'
There are a number of options you have at this point. You can explicitly supply the self argument to the partial:
import functools
class Foo(object):
def __init__(self):
def f(self, a, b):
print a + b
self.g = functools.partial(f, self, 1)
x = Foo()
x.g(2)
...or you would imbed the self and value of a in a closure:
class Foo(object):
def __init__(self):
a = 1
def f(b):
print a + b
self.g = f
x = Foo()
x.g(2)
These solutions are of course assuming that there is an as yet unspecified reason for assigning a method to the class in the constructor like this, as you can very easily just define a method directly on the class to do what you are doing here.
Edit: Here is an idea for a solution assuming the functions may be created for the class, instead of the instance:
class Foo(object):
pass
def make_binding(name):
def f(self, *args):
print 'Do %s with %s given %r.' % (name, self, args)
return f
for name in 'foo', 'bar', 'baz':
setattr(Foo, name, make_binding(name))
f = Foo()
f.foo(1, 2, 3)
f.bar('some input')
f.baz()
Gives you:
Do foo with <__main__.Foo object at 0x10053e3d0> given (1, 2, 3).
Do bar with <__main__.Foo object at 0x10053e3d0> given ('some input',).
Do baz with <__main__.Foo object at 0x10053e3d0> given ().
This will work. But I'm not sure if this is what you are looking for
class Foo(object):
def __init__(self):
def f(a,self,b):
print a+b
self.g = functools.partial(f,1, self) # <= passing `self` also.
x = Foo()
x.g(2)
this is simply a concrete example of what i believe is the most correct (and therefore pythonic :) way to solve -- as the best solution (definition on a class!) was never revealed -- #MikeBoers explanations are otherwise solid.
i've used this pattern quite a bit (recently for an proxied API), and it's survived untold production hours without the slightest irregularity.
from functools import update_wrapper
from functools import partial
from types import MethodType
class Basic(object):
def add(self, **kwds):
print sum(kwds.values())
Basic.add_to_one = MethodType(
update_wrapper(partial(Basic.add, a=1), Basic.add),
None,
Basic,
)
x = Basic()
x.add(a=1, b=9)
x.add_to_one(b=9)
...yields:
10
10
...the key take-home-point here is MethodType(func, inst, cls), which creates an unbound method from another callable (you can even use this to chain/bind instance methods to unrelated classes... when instantiated+called the original instance method will receive BOTH self objects!)
note the exclusive use of keyword arguments! while there might be a better way to handle, args are generally a PITA because the placement of self becomes less predictable. also, IME anyway, using *args, and **kwds in the bottom-most function has proven very useful later on.
functools.partialmethod() is available since python 3.4 for this purpose.
import functools
class Foo(object):
def __init__(self):
def f(a,self,b):
print a+b
self.g = functools.partialmethod(f,1)
x=Foo()
x.g(2)

Creating equivalent classes in Python?

I played around with overloading or masking classes in Python. Do the following code examples create equivalent classes?
class CustASample(object):
def __init__(self):
self.__class__.__name__ = "Sample"
def doSomething(self):
dummy = 1
and
class Sample(object):
def doSomething(self):
dummy = 1
EDIT: From the comments and and the good answer by gs, it occured to me, that I really wanted to ask: What "attributes" make these classes differ?
Because
>>> dir(a) == dir(b)
True
and
>>> print Sample
<class '__main__.Sample'>
>>> print CustASample
<class '__main__.Sample'>
but
>>> Sample == CustASample
False
No, they are still different.
a = CustASample()
b = Sample()
a.__class__ is b.__class__
-> False
Here's how you could do it:
class A(object):
def __init__(self):
self.__class__ = B
class B(object):
def bark(self):
print "Wuff!"
a = A()
b = B()
a.__class__ is b.__class__
-> True
a.bark()
-> Wuff!
b.bark()
-> Wuff!
Usually you would do it in the __new__ method instead of in __init__:
class C(object):
def __new__(cls):
return A()
To answer your updated question:
>>> a = object()
>>> b = object()
>>> a == b
False
Why would a not be equal to b, since both are just plain objects without attributes?
Well, that answer is simple. The == operator invokes __eq__, if it's available. But unless you define it yourself it's not. Instead of it a is b gets used.
is compares the ids of the objects. (In CPython the memory address.) You can get the id of an object like this:
>>> id(a)
156808
Classes also, not only instances, are objects. For example, you can get id(Sample). Try it and see that these two numbers differ, as differ the classes' memory locations. They are not the same object. It's like asking whether [] is [].
EDIT: Too late and the explanation by gs is better.

Categories

Resources