Or is everything a method?
Since everything is an object, a
def whatever:
is just a method of that file.py, right?
Python has functions. As everything is an object functions are objects too.
So, to use your example:
>>> def whatever():
... pass
...
>>> whatever
<function whatever at 0x00AF5F30>
When we use def we have created an object which is a function. We can, for example, look at an attribute of the object:
>>> whatever.func_name
'whatever'
In answer to your question - whatever() is not a method of file.py. It is better to think of it as a function object bound to the name whatever in the global namespace of file.py.
>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__d
oc__': None, 'whatever': <function whatever at 0x00AF5EB0>}
Or to look at it another way, there's nothing stopping us from binding the name whatever to a different object altogether:
>>> whatever
<function whatever at 0x00AF5F30>
>>> whatever = "string"
>>> whatever
'string'
There are other ways to create function objects. For example, lambdas:
>>> somelambda = lambda x: x * 2
>>> somelambda
<function <lambda> at 0x00AF5F30>
A method is like attribute of an object that is a function. What makes it a method is that the methods get bound to the object. This causes the object to get passed to the function as the first argument which we normally call self.
Let's define a class SomeClass with a method somemethod and an instance someobject:
>>> class SomeClass:
... def somemethod(one="Not Passed", two="Not passed"):
... print "one = %s\ntwo = %s" % (one,two)
...
>>> someobject = SomeClass()
Let's look at somemethod as an attribute:
>>> SomeClass.somemethod
<unbound method SomeClass.somemethod>
>>> someobject.somemethod
<bound method SomeClass.somemethod of <__main__.SomeClass instance at 0x00AFE030
We can see it's a bound method on the object and an unbound method on the class. So now let's call the method and see what happens:
>>> someobject.somemethod("Hello world")
one = <__main__.SomeClass instance at 0x00AFE030>
two = Hello world
As it's a bound method the first argument received by somemethod is the object and the second argument is the first argument in the method call. Let's call the method on the class:
>>> SomeClass.somemethod("Hello world")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method somemethod() must be called with SomeClass instance as first argument (got str instance instead)
Python complains because we're trying to call the method without giving it an object of the appropriate type. So we can fix this by passing the object "by hand":
>>> SomeClass.somemethod(someobject,"Hello world")
one = <__main__.SomeClass instance at 0x00AFE030>
two = Hello world
You might use method calls of this type - calling a method on a class - when you want to call a specific method from a superclass.
(It is possible to take a function and bind it to class to make it a method, but this is not something that you'd normally ever need to do.)
Unlike in Java in Python a file named file.py does not necessarily contain a class called file as you might expect if this was a java file named file.java.
In Python a file is a module which is really just a namespace (more comparable to a Java package than a Java class) and not a class. Consider the example file.py below:
def whatever_func():
print "What ever function"
class SomeClass(object):
def whatever_meth(self):
print "What ever method"
In the example above the file module/namespace contains an ordinary function named whatever_func and a class SomeClass which has a method whatever_meth.
Hmm... You can work with "whatever" as an ordinary function in file namespace.
Related
Consider a trivial example:
class C:
#staticmethod
def my_static_method():
print("static")
def my_instance_method(self):
print("self")
When I call C().my_static_method(), python doesn't pass the instance of C into my_static_method, and the descriptor that my_static_method references doesn't expect an instance of C, either.
This makes sense.
But then when I call C().my_instance_method(), how does python know to pass the instance of C that I'm calling my_instance_method from in as an argument, without me specifying anything?
As the link explains, function objects are descriptors! Just like staticmethod objects.
They have a __get__ method which returns a bound-method object, which essentially just partially applies the instance itself as the first positional argument. Consider:
>>> def foo(self):
... return self.bar
...
>>> class Baz:
... bar = 42
...
>>> baz = Baz()
>>> bound_method = foo.__get__(baz, Baz)
>>> bound_method
<bound method foo of <__main__.Baz object at 0x7ffcd001c7f0>>
>>> method()
42
By adding the #staticmethod decorator to my_static_method, you told python not to pass the calling instance of C into the function. So you can call this function as C.my_static_method().
By calling C() you created an instance of C. Then you called the non static function my_instance_method() which Python happily passed your new instance of C as the first parameter.
What happens when you call C.my_instance_method() ?
Rhetorical: You'll get a "missing one required arg self" exception -- since my_instance_method only works when calling from an instance unless you decorate it as static.
Of course you can still call the static member from an instance C().my_static_method() but you don't have a self param so no access to the instance.
The key point here is that methods are just functions that happen to be attributes of a class. The actual magic, in Python, happens in the attribute lookup process. The link you give explains earlier just how much happens every time x.y happens in Python. (Remember, everything is an object; that includes functions, classes, modules, type (which is an instance of itself)...)
This process is why descriptors can work at all; why we need explicit self; and why we can do fun things like calling a method with normal function call syntax (as long as we look it up from the class rather than an instance), alias it, mimic the method binding process with functools.partial....
Suppose we have c = C(). When you do c.my_instance_method (never mind calling it for now), Python looks for my_instance_method in type(c) (i.e., in the C class), and also checks if it's a descriptor, and also if it's specifically a data descriptor. Functions are non-data descriptors; even outside of a class, you can write
>>> def x(spam): return spam
...
>>> x.__get__
<method-wrapper '__get__' of function object at 0x...>
Because of the priority rules, as long as c doesn't directly have an attribute attached with the same name, the function will be found in C and its __get__ will be used. Note that the __get__ in question comes from the class - but it isn't using the same process as x.__get__ above. That code looks in the class because that's one of the places checked for an attribute lookup; but when c.my_instance_method redirects to C.my_instance_method.__get__, it's looking there directly - attaching a __get__ attribute directly to the function wouldn't change anything (which is why staticmethod is implemented as a class instead).
That __get__ implements the actual method binding. Let's pretend we found x as a method in the str class:
>>> x.__get__('spam', str)
<bound method x of 'spam'>
>>> x.__get__('spam', str)()
'spam'
Remember, although the function in question takes three arguments, we're calling __get__, itself, as a method - so x gets bound to it in the same way. Equivalently, and more faithful to the actual process:
>>> type(x).__get__(x, 'spam', str)
<bound method x of 'spam'>
>>> type(x).__get__(x, 'spam', str)()
'spam'
So what exactly is that "bound method", anyway?
>>> bound = type(x).__get__(x, 'spam', str)
>>> type(bound)
<class 'method'>
>>> bound.__call__
<method-wrapper '__call__' of method object at 0x...>
>>> bound.__func__
<function x at 0x...>
>>> bound.__self__
'spam'
>>> type(bound)(x, 'eggs')
<bound method x of 'eggs'>
Pretty much what you'd expect: it's a callable object that stores and uses the original function and self value, and does the obvious thing in __call__.
This is how we make static functions in Python:
class A:
#staticmethod
def fun():
print 'hello'
A.fun()
This works as expected and prints hello.
If it is a member function instead of a static one, we use self:
class A:
def fun(self):
print 'hello'
A().fun()
which also works as expected and prints hello.
My confusion is with the following case:
class A:
def fun():
print 'hello'
In the above case, there is no staticmethod, nor self. Python interpreter is okay with this definition. However, we cannot call it either of the above methods, namely:
A.fun()
A().fun()
both gives errors.
My question is: Is there any way that I can call this function? If not, why Python do not give me a syntax error in the first place?
Python doesn't give you a syntax error, because the binding of a method (which takes care of passing in self) is a runtime action.
Only when you look up a method on a class or instance, is a method being bound (because functions are descriptors they produce a method when looked up this way). This is done via the descriptor.__get__() method, which is called by the object.__getattribute__() method, which Python called when you tried to access the fun attribute on the A class or A() instance.
You can always 'unwrap' the bound method and reach for the un-wrapped function underneath to call it directly:
A.fun.__func__()
Incidentally, that's exactly what staticmethod does; it is there to 'intercept' the descriptor binding and return the raw function object instead of a bound method. In other words, staticmethod undoes the normal runtime method binding:
Demo:
>>> class A(object): pass
...
>>> def fun(): print 'hello!'
...
>>> fun.__get__(None, A) # binding to a class
<unbound method A.fun>
>>> fun.__get__(None, A)() # calling a bound function, fails as there is no first argument
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method fun() must be called with A instance as first argument (got nothing instead)
>>> fun.__get__(None, A).__func__ # access the wrapped function
<function fun at 0x100ba8378>
>>> staticmethod(fun).__get__(None, A) # staticmethod object just returns the function
<function fun at 0x100ba8378>
>>> staticmethod(fun).__get__(None, A)() # so calling it works
hello!
class Person():
pass;
def say_hi(self):
print 'hii'
me=Person()
me.say_hi=say_hi
me.say_hi()
Isn't the self argument automatically passed in python ? why why is calling me.say_hi() is giving a stack trace ?
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: say_hi() takes exactly 1 argument (0 given)
It's not passed in the way that you are doing it.
You would have to do.
import types
me.say_hi = types.MethodType(say_hi, me, Person)
for it to work.
When python instantiates a class, it essentially carries out the above procedure for each of the class methods. When you 'monkey-patch' a method onto an object in the way that you were trying to do it, it's not a bound method and just exists as a function in instance.__dict__. Calling it is no different than calling any other function. If you want to stick a method on an instance, you have to manually make it a method as shown above.
If you were to do
class Person(object):
pass
def say_hi(self):
print 'hii'
Person.say_hi = say_hi
me = Person()
me.say_hi()
then it would work because Python will create the method for you.
Chris Morgan put up an answer that shows this one in action. It's good stuff.
(This can act as some demonstration for aaronasterling's answer.)
Here are the definitions:
>>> class Person(object):
... def bound(self):
... print "Hi, I'm bound."
...
>>> def unbound(self):
... print "Hi, I'm unbound."
...
Note the types of these methods and functions.
>>> type(Person.bound)
<type 'instancemethod'>
>>> type(Person().bound)
<type 'instancemethod'>
>>> type(unbound)
<type 'function'>
>>> Person.unbound = unbound
When it gets set on the Person before instantiation, it gets bound.
>>> Person().bound()
Hi, I'm bound.
>>> Person().unbound()
Hi, I'm unbound.
However, if it's set after instantiation, it's still of type 'function'.
>>> me = Person()
>>> me.rebound = unbound
>>> type(me.rebound)
<type 'function'>
>>> type(me.unbound)
<type 'instancemethod'>
>>> me.rebound
<function unbound at 0x7fa05efac9b0>
>>> me.rebound()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound() takes exactly 1 argument (0 given)
The 'instancemethod' type can be used to bind a 'function' to an object. It's in the types module as MethodType.
>>> import types
>>> me.rebound = types.MethodType(unbound, me, Person)
Now it's bound properly.
>>> type(me.rebound)
<type 'instancemethod'>
>>> me.rebound()
Hi, I'm unbound.
>>> # Not true any more!
In this case say_hi is not method of your class. It is just reference to a function. This is why the self argument is not passed automatically.
Or just use:
class Person():
def say_hi(self):
print 'hii'
me=Person() me.say_hi=say_hi me.say_hi()
The self argument of a method is passed automatically. You don't have a method, but a function that is an attribute of an object. If you did Person.say_hi = say_hi, then Person().say_hi() would work as expected. A method is a function that's attribute of a class, not an instance, and self is passed only for methods.
Class attributes define how the instances should work, while instance attributes are just normal you access. This means that class attributes are modified when they are accessed from an instance (e.g. functions are turned into methods), while instance attributes are left unchanged.
>>> class A(object): pass
...
>>> def f(self): print self
...
>>> ob = A()
>>> A.f = f
>>> ob.g = f
>>> print ob.f
<bound method A.f of <__main__.A object at 0xb74204ec>>
>>> print ob.g
<function f at 0xb7412ae4>
>>> ob.f()
<__main__.A object at 0xb74204ec>
>>> ob.g('test')
test
Since A is a class, f, A().f and A.f are different things. Since ob is an object, f and ob.g are the same thing.
because the function say_hi() wasn't defined inside of the person class it doesn't know what self is, and when you call it it isn't passing self to the method. This would be like calling a static method.
you could do this though
me=Person()
me.say_hi=say_hi
me.say_hi(me)
No, self is not automatically passed to the object, because it has not been defined within the class block. Instead, you have defined a function, say_hi, in the wrong block. When you run it, 'self' in this context, is actually the first parameter of a function which is outside the class block, and therefore not a part of the class, hence the error.
i think you wanted to do this
say_hi(me)
but the usual way to program OO is this:
class Person:
def say_hi(self):
print 'hii'
me = Person()
me.say_hi()
maybe this works?
class Person():
def say_hi(self):
print 'hii'
me=Person()
me.say_hi()
I put the function inside the class because I feel thats what you wanted. Then you can call it later from the class object me.
If a variable refers to either a function or a class method, how can I find out which one it is and get the class type in case it is a class method especially when the class is still being declared as in the given example.
eg.
def get_info(function_or_method):
print function_or_method
class Foo(object):
def __init__(self):
pass
get_info(__init__)
def bar():
pass
get_info(bar)
Update to question after the first two responses from David and J. F. Sebastian
To reemphasize a point which J.F. Sebastian alluded to, I want to be able to distinguish it when the function is being declared within the class (when the type I am getting is a function and not a bound or unbound method). ie. where the first call to get_info(__init__) happens I would like to be able to detect that its a method being declared as a part of a class.
This question came up since I am putting a decorator around it and it gets a handle to the init function and I can't actually figure out if a method is being declared within a class or as a stand alone function
You can distinguish between the two by checking the type:
>>> type(bar)
<type 'function'>
>>> type(Foo.__init__)
<type 'instancemethod'>
or
>>> import types
>>> isinstance(bar, types.FunctionType)
True
>>> isinstance(bar, types.UnboundMethodType)
True
which is the way you'd do it in an if statement.
Also, you can get the class from the im_class attribute of the method:
>>> Foo.__init__.im_class
__main__.Foo
At the time you are calling get_info(__init__) (inside class definition) the __init__ is an ordinary function.
def get_info(function_or_method):
print function_or_method
class Foo(object):
def __init__(self):
pass
get_info(__init__) # function
def bar():
pass
get_info(Foo.__init__) # unbound method
get_info(Foo().__init__) # bound method
get_info(bar) # function
Output (CPython, IronPython):
<function __init__ at ...>
<unbound method Foo.__init__>
<bound method Foo.__init__ of <__main__.Foo object at ...>>
<function bar at ...>
Output (Jython):
<function __init__ 1>
<unbound method Foo.__init__>
<method Foo.__init__ of Foo instance 2>
<function bar 3>
To reemphasize a point which J.F. Sebastian alluded to, I want to be able to distinguish it when the function is being declared within the class (when the type I am getting is a function and not a bound or unbound method). ie. where the first call to get_info(__init__) happens I would like to be able to detect that its a method being declared as a part of a class.
This question came up since I am putting a decorator around it and it gets a handle to the init function and I can't actually figure out if a method is being declared within a class or as a stand alone function
You can't. J.F. Sebastian's answer is still 100% applicable. When the body of the class definition is being executed, the class itself doesn't exist yet. The statements (the __init__ function definition, and the get_info(__init__) call) happen in a new local namespace; at the time the call to get_info occurs, __init__ is a reference to the function in that namespace, which is indistinguishable from a function defined outside of a class.
What is the difference between the following class methods?
Is it that one is static and the other is not?
class Test(object):
def method_one(self):
print "Called method_one"
def method_two():
print "Called method_two"
a_test = Test()
a_test.method_one()
a_test.method_two()
In Python, there is a distinction between bound and unbound methods.
Basically, a call to a member function (like method_one), a bound function
a_test.method_one()
is translated to
Test.method_one(a_test)
i.e. a call to an unbound method. Because of that, a call to your version of method_two will fail with a TypeError
>>> a_test = Test()
>>> a_test.method_two()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method_two() takes no arguments (1 given)
You can change the behavior of a method using a decorator
class Test(object):
def method_one(self):
print "Called method_one"
#staticmethod
def method_two():
print "Called method two"
The decorator tells the built-in default metaclass type (the class of a class, cf. this question) to not create bound methods for method_two.
Now, you can invoke static method both on an instance or on the class directly:
>>> a_test = Test()
>>> a_test.method_one()
Called method_one
>>> a_test.method_two()
Called method_two
>>> Test.method_two()
Called method_two
Methods in Python are a very, very simple thing once you understood the basics of the descriptor system. Imagine the following class:
class C(object):
def foo(self):
pass
Now let's have a look at that class in the shell:
>>> C.foo
<unbound method C.foo>
>>> C.__dict__['foo']
<function foo at 0x17d05b0>
As you can see if you access the foo attribute on the class you get back an unbound method, however inside the class storage (the dict) there is a function. Why's that? The reason for this is that the class of your class implements a __getattribute__ that resolves descriptors. Sounds complex, but is not. C.foo is roughly equivalent to this code in that special case:
>>> C.__dict__['foo'].__get__(None, C)
<unbound method C.foo>
That's because functions have a __get__ method which makes them descriptors. If you have an instance of a class it's nearly the same, just that None is the class instance:
>>> c = C()
>>> C.__dict__['foo'].__get__(c, C)
<bound method C.foo of <__main__.C object at 0x17bd4d0>>
Now why does Python do that? Because the method object binds the first parameter of a function to the instance of the class. That's where self comes from. Now sometimes you don't want your class to make a function a method, that's where staticmethod comes into play:
class C(object):
#staticmethod
def foo():
pass
The staticmethod decorator wraps your class and implements a dummy __get__ that returns the wrapped function as function and not as a method:
>>> C.__dict__['foo'].__get__(None, C)
<function foo at 0x17d0c30>
Hope that explains it.
When you call a class member, Python automatically uses a reference to the object as the first parameter. The variable self actually means nothing, it's just a coding convention. You could call it gargaloo if you wanted. That said, the call to method_two would raise a TypeError, because Python is automatically trying to pass a parameter (the reference to its parent object) to a method that was defined as having no parameters.
To actually make it work, you could append this to your class definition:
method_two = staticmethod(method_two)
or you could use the #staticmethod function decorator.
>>> class Class(object):
... def __init__(self):
... self.i = 0
... def instance_method(self):
... self.i += 1
... print self.i
... c = 0
... #classmethod
... def class_method(cls):
... cls.c += 1
... print cls.c
... #staticmethod
... def static_method(s):
... s += 1
... print s
...
>>> a = Class()
>>> a.class_method()
1
>>> Class.class_method() # The class shares this value across instances
2
>>> a.instance_method()
1
>>> Class.instance_method() # The class cannot use an instance method
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method instance_method() must be called with Class instance as first argument (got nothing instead)
>>> Class.instance_method(a)
2
>>> b = 0
>>> a.static_method(b)
1
>>> a.static_method(a.c) # Static method does not have direct access to
>>> # class or instance properties.
3
>>> Class.c # a.c above was passed by value and not by reference.
2
>>> a.c
2
>>> a.c = 5 # The connection between the instance
>>> Class.c # and its class is weak as seen here.
2
>>> Class.class_method()
3
>>> a.c
5
method_two won't work because you're defining a member function but not telling it what the function is a member of. If you execute the last line you'll get:
>>> a_test.method_two()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method_two() takes no arguments (1 given)
If you're defining member functions for a class the first argument must always be 'self'.
Accurate explanation from Armin Ronacher above, expanding on his answers so that beginners like me understand it well:
Difference in the methods defined in a class, whether static or instance method(there is yet another type - class method - not discussed here so skipping it), lay in the fact whether they are somehow bound to the class instance or not. For example, say whether the method receives a reference to the class instance during runtime
class C:
a = []
def foo(self):
pass
C # this is the class object
C.a # is a list object (class property object)
C.foo # is a function object (class property object)
c = C()
c # this is the class instance
The __dict__ dictionary property of the class object holds the reference to all the properties and methods of a class object and thus
>>> C.__dict__['foo']
<function foo at 0x17d05b0>
the method foo is accessible as above. An important point to note here is that everything in python is an object and so references in the dictionary above are themselves pointing to other objects. Let me call them Class Property Objects - or as CPO within the scope of my answer for brevity.
If a CPO is a descriptor, then python interpretor calls the __get__() method of the CPO to access the value it contains.
In order to determine if a CPO is a descriptor, python interpretor checks if it implements the descriptor protocol. To implement descriptor protocol is to implement 3 methods
def __get__(self, instance, owner)
def __set__(self, instance, value)
def __delete__(self, instance)
for e.g.
>>> C.__dict__['foo'].__get__(c, C)
where
self is the CPO (it could be an instance of list, str, function etc) and is supplied by the runtime
instance is the instance of the class where this CPO is defined (the object 'c' above) and needs to be explicity supplied by us
owner is the class where this CPO is defined(the class object 'C' above) and needs to be supplied by us. However this is because we are calling it on the CPO. when we call it on the instance, we dont need to supply this since the runtime can supply the instance or its class(polymorphism)
value is the intended value for the CPO and needs to be supplied by us
Not all CPO are descriptors. For example
>>> C.__dict__['foo'].__get__(None, C)
<function C.foo at 0x10a72f510>
>>> C.__dict__['a'].__get__(None, C)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__get__'
This is because the list class doesnt implement the descriptor protocol.
Thus the argument self in c.foo(self) is required because its method signature is actually this C.__dict__['foo'].__get__(c, C) (as explained above, C is not needed as it can be found out or polymorphed)
And this is also why you get a TypeError if you dont pass that required instance argument.
If you notice the method is still referenced via the class Object C and the binding with the class instance is achieved via passing a context in the form of the instance object into this function.
This is pretty awesome since if you chose to keep no context or no binding to the instance, all that was needed was to write a class to wrap the descriptor CPO and override its __get__() method to require no context.
This new class is what we call a decorator and is applied via the keyword #staticmethod
class C(object):
#staticmethod
def foo():
pass
The absence of context in the new wrapped CPO foo doesnt throw an error and can be verified as follows:
>>> C.__dict__['foo'].__get__(None, C)
<function foo at 0x17d0c30>
Use case of a static method is more of a namespacing and code maintainability one(taking it out of a class and making it available throughout the module etc).
It maybe better to write static methods rather than instance methods whenever possible, unless ofcourse you need to contexualise the methods(like access instance variables, class variables etc). One reason is to ease garbage collection by not keeping unwanted reference to objects.
that is an error.
first of all, first line should be like this (be careful of capitals)
class Test(object):
Whenever you call a method of a class, it gets itself as the first argument (hence the name self) and method_two gives this error
>>> a.method_two()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method_two() takes no arguments (1 given)
The second one won't work because when you call it like that python internally tries to call it with the a_test instance as the first argument, but your method_two doesn't accept any arguments, so it wont work, you'll get a runtime error.
If you want the equivalent of a static method you can use a class method.
There's much less need for class methods in Python than static methods in languages like Java or C#. Most often the best solution is to use a method in the module, outside a class definition, those work more efficiently than class methods.
The call to method_two will throw an exception for not accepting the self parameter the Python runtime will automatically pass it.
If you want to create a static method in a Python class, decorate it with the staticmethod decorator.
Class Test(Object):
#staticmethod
def method_two():
print "Called method_two"
Test.method_two()
Please read this docs from the Guido First Class everything Clearly explained how Unbound, Bound methods are born.
Bound method = instance method
Unbound method = static method.
The definition of method_two is invalid. When you call method_two, you'll get TypeError: method_two() takes 0 positional arguments but 1 was given from the interpreter.
An instance method is a bounded function when you call it like a_test.method_two(). It automatically accepts self, which points to an instance of Test, as its first parameter. Through the self parameter, an instance method can freely access attributes and modify them on the same object.
Unbound Methods
Unbound methods are methods that are not bound to any particular class instance yet.
Bound Methods
Bound methods are the ones which are bound to a specific instance of a class.
As its documented here, self can refer to different things depending on the function is bound, unbound or static.
Take a look at the following example:
class MyClass:
def some_method(self):
return self # For the sake of the example
>>> MyClass().some_method()
<__main__.MyClass object at 0x10e8e43a0># This can also be written as:>>> obj = MyClass()
>>> obj.some_method()
<__main__.MyClass object at 0x10ea12bb0>
# Bound method call:
>>> obj.some_method(10)
TypeError: some_method() takes 1 positional argument but 2 were given
# WHY IT DIDN'T WORK?
# obj.some_method(10) bound call translated as
# MyClass.some_method(obj, 10) unbound method and it takes 2
# arguments now instead of 1
# ----- USING THE UNBOUND METHOD ------
>>> MyClass.some_method(10)
10
Since we did not use the class instance — obj — on the last call, we can kinda say it looks like a static method.
If so, what is the difference between MyClass.some_method(10) call and a call to a static function decorated with a #staticmethod decorator?
By using the decorator, we explicitly make it clear that the method will be used without creating an instance for it first. Normally one would not expect the class member methods to be used without the instance and accesing them can cause possible errors depending on the structure of the method.
Also, by adding the #staticmethod decorator, we are making it possible to be reached through an object as well.
class MyClass:
def some_method(self):
return self
#staticmethod
def some_static_method(number):
return number
>>> MyClass.some_static_method(10) # without an instance
10
>>> MyClass().some_static_method(10) # Calling through an instance
10
You can’t do the above example with the instance methods. You may survive the first one (as we did before) but the second one will be translated into an unbound call MyClass.some_method(obj, 10) which will raise a TypeError since the instance method takes one argument and you unintentionally tried to pass two.
Then, you might say, “if I can call static methods through both an instance and a class, MyClass.some_static_method and MyClass().some_static_method should be the same methods.” Yes!