Are there any benefits from using a #staticmethod? - python

I was wondering if you use #staticmethod decorator in your code.
Personally I don't use it, since it takes more letters to write #staticmethod then self.
The only benefit (which comes to me) from using it may be a better clarity of a code, but since I usually write a method description for sphinx, I always state whether a method is using object or not.
Or maybe I should start using #staticmethod decorator ?

Whether to use #staticmethod or not depends on what you want to achieve. Ignoring the decorator because there is more to type is a rather silly reason (no offense!) and indicates that you have not understood the concept of a static method in Python!
Static methods are independent of the class and any class instance. They only use the class scope as a namespace. If you omit the #staticmethod decorator, you are creating an instance method that cannot be used without constructing an instance.
Here is a very simple class Foo:
>>> class Foo(object):
... #staticmethod
... def foo():
... print 'foo'
...
... def bar(self):
... print 'bar'
Now, Foo.foo() is a static method that can be called directly:
>>> Foo.foo()
foo
Foo.bar() on the other hand is an instance method, that can only be called from instances (objects) of Foo:
>>> Foo.bar()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with Foo instance as first argument (got nothing instead)
>>> foo = Foo()
>>> foo.bar()
bar
To answer your question: If you want to define a static method, use #staticmethod. Otherwise, don't.
If you have a method that does not use self, and therefore could be written as a static method, ask yourself: Will you ever want to access this function from outside without having an instance? Most of the times, the answer will be: No.

Assume that we want to define abs method in class Math, then we have two choices:
class Math():
def abs(n):
if n>0:
return n
else:
return -n
class Math2():
#staticmethod
def abs(n):
if n>0:
return n
else:
return -n
In Python2:
>>> Math.abs(-2)
TypeError: unbound method abs() must be called with Math instance as
first argument (got int instance instead)
>>>Math().abs(-2)
TypeError: abs() takes exactly 1 argument (2 given)
>>> Math2.abs(-2)
2
>>> Math2().abs(-2)
2
python2 automatically takes Math().abs(-2) as Math().abs(self,-2),so that you have to use #staticmethod.
In Python3
>>>Math.abs(-3)
3
>>>Math().abs(-3)
TypeError: abs() takes 1 positional argument but 2 were given
>>>Math2.abs(-3)
3
>>>Math2().abs(-3)
3
In python3, you can use classname.method() without static method, but it will raise TypeError when someone tries to use instance.method().

#staticmethod decorator saves you typing and improves readability.
class Example:
#staticmethod
def some_method():
return
is the same as:
class Example:
def some_method():
return
some_method = staticmethod(some_method)
I think you may be confused about what a static method is in Python as the terminology differs from other languages. A regular method is "bound" to the instance (self), a class method is "bound" to the class (cls) while a static method is not "bound" at all (and can not access instance nor class attributes.
See:
http://docs.python.org/library/functions.html#classmethod
http://docs.python.org/library/functions.html#staticmethod

In addition to the previous answers,
from pythons doc #staticmethod :
It can be called either on the class (such as C.f()) or on an instance (such as C().f()). The instance is ignored except for its class.
class Test:
#staticmethod
def Foo():
print('static Foo')
def Bar():
print('static Bar')
Test.foo() # static Foo
Test.bar() # static Bar
obj = Test()
obj.foo() # static Foo ; note that you can call it from class instance
obj.bar() # ERROR

Related

Difference between having #staticmethod and not having it

In Python 3.x what can I do with bar() that I cannot do with foo()?
class A:
def foo():
print("some code")
#staticmethod
def bar():
print("some code")
Note: I initially forgot to specify self as an argument to foo(), but I'm leaving the mistake there, since the answers andress that.
a staticmethod is a method that does not require an object as its first parameter. This means it is a method useful to the class itself and all instantiations of it, rather than just instances of it (object initialized as A().
What this means in practical terms, is that Python does not implicitly send the object itself as a parameter. Your first method will break once you call it:
>>> a.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes 0 positional arguments but 1 was given
This is because Python supplies object methods with the object itself as a first parameter. Hence the ubiquitous self argument:
def foo(self): #Proper signature
On the other hand,
A.bar()
will work just fine, and so will
a.bar()
The object is not supplied as a first argument. Use staticmethods for methods that are supposed to be helpful to the class and its instances, but do not require knowledge of either. Usually I use these as utility functions.
Note there is a third version, a classmethod, which is similar to a regular method in that it accepts a first parameter by default - the class of the caller. In this case the minimal signature is
#classmethod
def operateOnClass(cls):
Use this to make changes that affect all instances, such as changing class variables.
bar() can be called from an uninstantiated class object. foo() needs to be fed self as an argument, and as such can only be called from an object already declared as an instance of class A

Why do I need to pass the class instance or object to a function definition inside a class? [duplicate]

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!

Do we really need #staticmethod decorator in python to declare static method

I am curious about why we need the #staticmethod decorator to declare method as static. I was reading about static methods in Python, and I came to know that static method can be callable without instantiating its class.
So I tried the two examples below, but both do the same:
class StatMethod:
def stat():
print("without Decorator")
class StatMethod_with_decorator:
#staticmethod
def stat():
print("With Decorator")
If I call the stat() method on the class directly, both print/show the values below:
>> StatMethod.stat()
without Decorator
>> StatMethod_with_decorator.stat()
With Decorator
You need the decorator if you intend to try to call the #staticmethod from the instance of the class instead of of the class directly
class Foo():
def bar(x):
return x + 5
>>> f = Foo()
>>> f.bar(4)
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
f.bar(4)
TypeError: bar() takes 1 positional argument but 2 were given
Now if I declare #staticmethod the self argument isn't passed implicitly as the first argument
class Foo():
#staticmethod
def bar(x):
return x + 5
>>> f = Foo()
>>> f.bar(4)
9
The documentation describes some transformations that are done when calling a user defined method:
Note that the transformation from function object to (unbound or
bound) method object happens each time the attribute is retrieved from
the class or instance. In some cases, a fruitful optimization is to
assign the attribute to a local variable and call that local variable.
Also notice that this transformation only happens for user-defined
functions; other callable objects (and all non-callable objects) are
retrieved without transformation. It is also important to note that
user-defined functions which are attributes of a class instance are
not converted to bound methods; this only happens when the function is
an attribute of the class.
For methods marked as staticmethod this is different:
Static method objects provide a way of defeating the transformation of
function objects to method objects described above. A static method
object is a wrapper around any other object, usually a user-defined
method object. When a static method object is retrieved from a class
or a class instance, the object actually returned is the wrapped
object, which is not subject to any further transformation. Static
method objects are not themselves callable, although the objects they
wrap usually are. Static method objects are created by the built-in
staticmethod() constructor.
if function has some parameters, then call non static method would be failed
and static method didn't use the local variables in the class, but the class method will be
Update: In python 3.10 you dont need the decorator any more
Just my simple approach here. Forget the decorators. Use the class directly (Python 3.8):
class MyClass:
def myMethod(self, myValue):
print(myValue)
MyClass.myMethod(None, "hi")
Or both:
MyClass.myMethod(None, "hi from class")
myInstance = myClass()
myInstance.myMethod2("hi from instance")

Python: Regular method and static method with same name

Introduction
I have a Python class, which contains a number of methods. I want one of those methods to have a static counterpart—that is, a static method with the same name—which can handle more arguments. After some searching, I have found that I can use the #staticmethod decorator to create a static method.
Problem
For convenience, I have created a reduced test case which reproduces the issue:
class myclass:
#staticmethod
def foo():
return 'static method'
def foo(self):
return 'public method'
obj = myclass()
print(obj.foo())
print(myclass.foo())
I expect that the code above will print the following:
public method
static method
However, the code prints the following:
public method
Traceback (most recent call last):
File "sandbox.py", line 14, in <module>
print(myclass.foo())
TypeError: foo() missing 1 required positional argument: 'self'
From this, I can only assume that calling myclass.foo() tries to call its non-static counterpart with no arguments (which won't work because non-static methods always accept the argument self). This behavior baffles me, because I expect any call to the static method to actually call the static method.
I've tested the issue in both Python 2.7 and 3.3, only to receive the same error.
Questions
Why does this happen, and what can I do to fix my code so it prints:
public method
static method
as I would expect?
While it's not strictly possible to do, as rightly pointed out, you could always "fake" it by redefining the method on instantiation, like this:
class YourClass(object):
def __init__(self):
self.foo = self._instance_foo
#staticmethod
def foo():
print "Static!"
def _instance_foo(self):
print "Instance!"
which would produce the desired result:
>>> YourClass.foo()
Static!
>>> your_instance = YourClass()
>>> your_instance.foo()
Instance!
A similar question is here: override methods with same name in python programming
functions are looked up by name, so you are just redefining foo with an instance method. There is no such thing as an overloaded function in Python. You either write a new function with a separate name, or you provide the arguments in such a way that it can handle the logic for both.
In other words, you can't have a static version and an instance version of the same name. If you look at its vars you'll see one foo.
In [1]: class Test:
...: #staticmethod
...: def foo():
...: print 'static'
...: def foo(self):
...: print 'instance'
...:
In [2]: t = Test()
In [3]: t.foo()
instance
In [6]: vars(Test)
Out[6]: {'__doc__': None, '__module__': '__main__', 'foo': <function __main__.foo>}
Because attribute lookup in Python is something within the programmer's control, this sort of thing is technically possible. If you put any value into writing code in a "pythonic" way (using the preferred conventions and idioms of the python community), it is very likely the wrong way to frame a problem / design. But if you know how descriptors can allow you to control attribute lookup, and how functions become bound functions (hint: functions are descriptors), you can accomplish code that is roughly what you want.
For a given name, there is only one object that will be looked up on a class, regardless of whether you are looking the name up on an instance of the class, or the class itself. Thus, the thing that you're looking up has to deal with the two cases, and dispatch appropriately.
(Note: this isn't exactly true; if an instance has a name in its attribute namespace that collides with one in the namespace of its class, the value on the instance will win in some circumstances. But even in those circumstances, it won't become a "bound method" in the way that you probably would wish it to.)
I don't recommend designing your program using a technique such as this, but the following will do roughly what you asked. Understanding how this works requires a relatively deep understanding of python as a language.
class StaticOrInstanceDescriptor(object):
def __get__(self, cls, inst):
if cls is None:
return self.instance.__get__(self)
else:
return self.static
def __init__(self, static):
self.static = static
def instance(self, instance):
self.instance = instance
return self
class MyClass(object):
#StaticOrInstanceDescriptor
def foo():
return 'static method'
#foo.instance
def foo(self):
return 'public method'
obj = MyClass()
print(obj.foo())
print(MyClass.foo())
which does print out:
% python /tmp/sandbox.py
static method
public method
Ended up here from google so thought I would post my solution to this "problem"...
class Test():
def test_method(self=None):
if self is None:
print("static bit")
else:
print("instance bit")
This way you can use the method like a static method or like an instance method.
When you try to call MyClass.foo(), Python will complain since you did not pass the one required self argument. #coderpatros's answer has the right idea, where we provide a default value for self, so its no longer required. However, that won't work if there are additional arguments besides self. Here's a function that can handle almost all types of method signatures:
import inspect
from functools import wraps
def class_overload(cls, methods):
""" Add classmethod overloads to one or more instance methods """
for name in methods:
func = getattr(cls, name)
# required positional arguments
pos_args = 1 # start at one, as we assume "self" is positional_only
kwd_args = [] # [name:str, ...]
sig = iter(inspect.signature(func).parameters.values())
next(sig)
for s in sig:
if s.default is s.empty:
if s.kind == s.POSITIONAL_ONLY:
pos_args += 1
continue
elif s.kind == s.POSITIONAL_OR_KEYWORD:
kwd_args.append(s.name)
continue
break
#wraps(func)
def overloaded(*args, **kwargs):
# most common case: missing positional arg or 1st arg is not a cls instance
isclass = len(args) < pos_args or not isinstance(args[0], cls)
# handle ambiguous signatures, func(self, arg:cls, *args, **kwargs);
# check if missing required positional_or_keyword arg
if not isclass:
for i in range(len(args)-pos_args,len(kwd_args)):
if kwd_args[i] not in kwargs:
isclass = True
break
# class method
if isclass:
return func(cls, *args, **kwargs)
# instance method
return func(*args, **kwargs)
setattr(cls, name, overloaded)
class Foo:
def foo(self, *args, **kwargs):
isclass = self is Foo
print("foo {} method called".format(["instance","class"][isclass]))
class_overload(Foo, ["foo"])
Foo.foo() # "foo class method called"
Foo().foo() # "foo instance method called"
You can use the isclass bool to implement the different logic for class vs instance method.
The class_overload function is a bit beefy and will need to inspect the signature when the class is declared. But the actual logic in the runtime decorator (overloaded) should be quite fast.
There's one signature that this solution won't work for: a method with an optional, first, positional argument of type Foo. It's impossible to tell if we are calling the static or instance method just by the signature in this case. For example:
def bad_foo(self, other:Foo=None):
...
bad_foo(f) # f.bad_foo(None) or Foo.bad_foo(f) ???
Note, this solution may also report an incorrect isclass value if you pass in incorrect arguments to the method (a programmer error, so may not be important to you).
We can get a possibly more robust solution by doing the reverse of this: first start with a classmethod, and then create an instance method overload of it. This is essentially the same idea as #Dologan's answer, though I think mine is a little less boilerplatey if you need to do this on several methods:
from types import MethodType
def instance_overload(self, methods):
""" Adds instance overloads for one or more classmethods"""
for name in methods:
setattr(self, name, MethodType(getattr(self, name).__func__, self))
class Foo:
def __init__(self):
instance_overload(self, ["foo"])
#classmethod
def foo(self, *args, **kwargs):
isclass = self is Foo
print("foo {} method called:".format(["instance","class"][isclass]))
Foo.foo() # "foo class method called"
Foo().foo() # "foo instance method called"
Not counting the code for class_overload or instance_overload, the code is equally succinct. Often signature introspection is touted as the "pythonic" way to do these kinds of things. But I think I'd recommend using the instance_method solution instead; isclass will be correct for any method signature, including cases where you call with incorrect arguments (a programmer error).

Explanation of a decorator class in python

While reading up about some python module I encountered this decorator class:
# this decorator lets me use methods as both static and instance methods
class omnimethod(object):
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
return functools.partial(self.func, instance)
What I know about decorators, is that the can extend functionality (e.g. for a function). Could someone be so kind and explain to me why the class above is useful and how it exactly works?
It is used in the code this way:
#omnimethod:
def some_function(...):
pass
Another question:
I encountered this piece of code in the same file:
#property
def some_other_function(...):
pass
#property is not defined anywhere in the file. Is this some standard decorator? If yes, what does it do? Google couldn't help me on this case.
By the way, here is the source where I found the code: http://code.xster.net/pygeocoder/src/c9460febdbd1/pygeocoder.py
that omnimethod is very clever. It uses some very subtle tricks to do it's job. Let's start at the beginning.
You probably already know that decorator syntax is just sugar for function application, ie:
#somedecorator
def somefunc(...):
pass
# is the same thing as
def somefunc(...):
pass
somefunc = somedecorator(somefunc)
so somefunc is actually an omnimethod instance, not the function that had been defined. what's interesting about this is that omnimethod also implements the descriptor interface. If a class attribute defines a __get__ method, then whenever that attribute is mentioned, the interpreter instead calls __get__ on that object, and returns that instead of returning the attribute itself.
the __get__ method is always called with instance as first argument, and the class of that instance as second argument. If the attribute was actually looked up from the class itself, then instance will be None.
The last bit of trickery is functools.partial, which is the python way of function currying. when you use partial, you pass it a function and some arguments, and it returns a new function, that when called, will call the original function with the original arguments in addition to whichever arguments you passed in later. omnimethod uses this technique to populate the self parameter to the function it wraps.
Here's what that looks like. a regular method can be called when you read it from an instance but you can't use it from the class itself. you get an unbound TypeError
>>> class Foo(object):
... def bar(self, baz):
... print self, baz
...
>>> f = Foo()
>>> f.bar('apples')
<__main__.Foo object at 0x7fe81ab52f90> apples
>>> Foo.bar('quux')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with
Foo instance as first argument (got str instance instead)
>>> Foo.bar(None, 'quux')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with
Foo instance as first argument (got NoneType instance instead)
>>>
Python provides a bultin decorator classmethod (and also staticmethod, but nevermind that), that will allow you to use it at the class level, but it never gets to see the instance. it always recieves the class as it's first argument.
>>> class Foo(object):
... #classmethod
... def bar(cls, baz):
... print cls, baz
...
>>> f = Foo()
>>> Foo.bar('abc')
<class '__main__.Foo'> abc
>>> f.bar('def')
<class '__main__.Foo'> def
>>>
By it's bit of cleverness, omnimethod gives you a little bit of both.
>>> class Foo(object):
... #omnimethod
... def bar(self, baz):
... print self, baz
...
>>> f = Foo()
>>> Foo.bar('bananas')
None bananas
>>> f.bar('apples')
<__main__.Foo object at 0x7fe81ab52f90> apples
>>>
omnimethod does what it says in the comment; it will let you call some_function as either a 'static function' on a class or as a function on an instance of the class. #property is a standard decorator (see the python docs) that exposes a function in a way that makes it look like a simple instance variable.
class B:
#omnimethod
def test(self):
print 1
#property
def prop(self):
return 2
>>> b = B()
>>> b.test()
1
>>> B.test()
1
>>> b.prop
2

Categories

Resources