Bind a method that calls other methods inside the class - python

I periodically find myself attempting to slightly abuse some of the dinamicity allowed by python (I'm using python3 here, but there shouldn't be many differences).
In this case, I wanted to split a single test_ method in my unittest.TestCase, to several methods created at runtime.
(this was a Kata about roman numerals, but I actually didn't TDD: I wrote the test later)
This is the test:
class TestNumbers(TestCase):
def test_number(self):
for i in range(3000):
self.assertEqual(i, roman_to_int(int_to_roman(i)))
this is how I tried to write it:
from functools import partial
from types import MethodType
class TestNumbers(TestCase):
pass
def test_number(self, n):
self.assertEqual(n, roman_to_int(int_to_roman(n)))
for i in range(3000):
name = str(i)
test_method = MethodType(partial(test_number, n=i), TestNumbers)
setattr(TestNumbers, "test" + name, test_method)
(alternatively, I also tried to dinamically create lots of TestCase subclasses and setattr(globals(), ...) them)
I know: this doesn't really has much purpose, it's also probably slower, etc.etc. but this is just a POC and I'm trying to understand how I can get it to work
by using MethodType, the test becomes a bound method, but inside, assertEqual apparently becomes a function, and when trying to call it it'll fail with TypeError: assertEqual() takes at least 3 arguments (2 given)
I tried to change test_number to
def test_number(self, n):
self.assertEqual(self, n, roman_to_int(int_to_roman(n)))
but this will only unearth the same problem deeper in hidden TestCase methods: TypeError: _getAssertEqualityFunc() takes exactly 3 arguments (2 given)
I looked here on stackoverflow and found similar questions (like Python: Bind an Unbound Method? ), but none of those deal with binding a method that inside of it calls other bound methods of the target class
I also tried to look into metaclasses ( http://docs.python.org/py3k/reference/datamodel.html#customizing-class-creation ) but it doesn't seem to match with what I'm trying to do

On Python 2 there are functions, unbound and bound methods. Binding a method to a class as a instance doesn't make it an unbound method, is makes it the equivalent of a classmethod or a metaclass-method.
On Python 3 there are no longer bound and unbound methods, just functions and methods, so if you're getting assertEqual as a function, it means your testx method is not being bound to the instance and that's the real problem.
On Python 2 all you have to do is assign None to the instance on the MethodType call and it would work.
So, replace:
test_method = MethodType(partial(test_number, n=i), TestNumbers)
For:
test_method = MethodType(partial(test_number, n=i), None, TestNumbers)
On Python 3 just assigning the function to the class would work, like the other answer suggests, but the real issue in your case is that partial objects don't become methods.
An easy solution for your case is to use lambda instead of partial.
Instead of:
test_method = MethodType(partial(test_number, n=i), TestNumbers)
Use:
test_method = lambda self: test_number(self, i)
And it should work...
The real neat solution would be to rewrite partial in order to return a real function with the parameters you want. You can create a instance of function with everything from the older one and the extra default argument. Something like this:
code = test_number.__code__
globals = test_number.__globals__
closure = test_number.__closure__
testx = FunctionType(code, globals, "test"+name, (i,), closure)
setattr(TestNumbers, "test" + name, testx)

If you're adding the method directly to the class then there's no need to bind it yourself.
class C(object):
def __init__(self):
self.foo = 42
def getfoo(self):
return self.foo
C.getfoo = getfoo
c=C()
print(c.getfoo())

Related

How to override a method in python of an object and call super?

I have an Object of the following class which inherates from the algorithm class.
class AP(Algorithm):
def evaluate(self, u):
return self.stuff *2 +u
The Algorithm class has a method called StoppingCritiria.
At some point in the project the object objAP = AP() gets created. Later on I can then actually access it.
And at that point in time I want to override the method StoppingCriteria by some function which calls the old StoppingCriteria.
I tried simply
def new_stopping(self):
return super().StoppingCriteria() and custom(self.u)
objAP.StoppingCriteria = newStoppingCriteria
But that did not work. What did work were two rather inconviniend solutions:
New AP class (not desirable since I possibly need to do that for lots of classes)
class AP_custom(AP):
def StoppingCriteria(self):
return super().StoppingCriteria() and custom(self)
Override the Method but not using super but rather copy pasting the code into the new function and adding my code to that. Not desirable since I want to changes in the original method to be applyed to my new function as well.
See Override a method at instance level for many possible solutions. None of them will really work with super though, since you're simply not defining the replacement function in a class. You can define it slightly differently though for it to work:
class Foo:
def bar(self):
print('bar')
f = Foo()
def _bar(self):
type(self).bar(self) # or Foo.bar(self)
print('baz')
from typing import MethodType
f.bar = MethodType(_bar, f)
f.bar() # outputs bar baz
Since you're replacing the method at the instance level, you don't really need to access the method of the super class, you just want to access the method of the class, which still exists in its original form.

How are Python static methods useful (except as a namespace)? [duplicate]

This question already has answers here:
Difference between #staticmethod and #classmethod
(35 answers)
Why do we use #staticmethod?
(4 answers)
Closed last month.
I ran into unbound method error in python with this code:
import random
class Sample(object):
def drawSample(samplesize, List):
sample = random.sample(List, samplesize)
return sample
Choices=range(100)
print(Sample.drawSample(5, Choices))
I was able to fix the problem by adding #staticmethod to the method. However, I don't really understand the situation.
What is the point of using "static" methods? Why does it solve the problem in this code, and why are they ever necessary? Conversely, why would I ever not want to do it (i.e., why is extra code needed to make the method static)?
See this article for detailed explanation.
TL;DR
1.It eliminates the use of self argument.
2.It reduces memory usage because Python doesn't have to instantiate a bound-method for each object instiantiated:
>>>RandomClass().regular_method is RandomClass().regular_method
False
>>>RandomClass().static_method is RandomClass().static_method
True
>>>RandomClass.static_method is RandomClass().static_method
True
3.It improves code readability, signifying that the method does not depend on state of the object itself.
4.It allows for method overriding in that if the method were defined at the module-level (i.e. outside the class) a subclass would not be able to override that method.
Static methods have limited use, because they don't have access to the attributes of an instance of a class (like a regular method does), and they don't have access to the attributes of the class itself (like a class method does).
So they aren't useful for day-to-day methods.
However, they can be useful to group some utility function together with a class - e.g. a simple conversion from one type to another - that doesn't need access to any information apart from the parameters provided (and perhaps some attributes global to the module.)
They could be put outside the class, but grouping them inside the class may make sense where they are only applicable there.
You can also reference the method via an instance or the class, rather than the module name, which may help the reader understand to what instance the method is related.
This is not quite to the point of your actual question, but since you've said you are a python newbie perhaps it will be helpful, and no one else has quite come out and said it explicitly.
I would never have fixed the above code by making the method a static method. I would either have ditched the class and just written a function:
def drawSample(samplesize,List):
sample=random.sample(List,samplesize)
return sample
Choices=range(100)
print drawSample(5,Choices)
If you have many related functions, you can group them in a module - i.e, put them all in the same file, named sample.py for example; then
import sample
Choices=range(100)
print sample.drawSample(5,Choices)
Or I would have added an __init__ method to the class and created an instance that had useful methods:
class Sample(object):
'''This class defines various methods related to the sample'''
def __init__(self, thelist):
self.list = thelist
def draw_sample(self, samplesize):
sample=random.sample(self.list,samplesize)
return sample
choices=Sample(range(100))
print choices.draw_sample(5)
(I also changed the case conventions in the above example to match the style recommended by PEP 8.)
One of the advantages of Python is that it doesn't force you to use classes for everything. You can use them only when there is data or state that should be associated with the methods, which is what classes are for. Otherwise you can use functions, which is what functions are for.
Why one would want to define static methods?
Suppose we have a class called Math then
nobody will want to create object of class Math
and then invoke methods like ceil and floor and fabs on it.
So we make them static.
For example doing
>> Math.floor(3.14)
is much better than
>> mymath = Math()
>> mymath.floor(3.14)
So they are useful in some way. You need not create an instance of a class to use them.
Why are not all methods defined as static methods?
They don't have access to instance variables.
class Foo(object):
def __init__(self):
self.bar = 'bar'
def too(self):
print self.bar
#staticmethod
def foo():
print self.bar
Foo().too() # works
Foo.foo() # doesn't work
That is why we don't make all the methods static.
The alternatives to a staticmethod are: classmethod, instancemethod, and function. If you don't know what these are, scroll down to the last section. If a staticmethod is better than any of these alternatives, depends on for what purpose it is written.
advantages of the Python static method
If you don't need access to the attributes or methods of the class or instance, a staticmethod is better than a classmethod or instancemethod. That way it is clear (from the #staticmethod decorator) that the class' and instance's state is not read or modified. However, using a function makes that distinction even clearer (see disadvantages).
The call signature of a staticmethod is the same as that of a classmethod or instancemethod, namely <instance>.<method>(<arguments>). Hence it can easily be replaced by one of the three if that is needed later on or in a derived class. You can't do that with a simple function.
A staticmethod can be used instead of a function to make clear that it subjectively belongs to a class and to prevent namespace conflicts.
disadvantages of the Python static method
It cannot access attributes or methods of the instance or class.
The call signature of a staticmethod is the same as that of a classmethod or instancemethod. This masks the fact that the staticmethod does not actually read or modify any object information. This makes code harder to read. Why not just use a function?
A staticmethod is difficult to re-use if you ever need to call it from outside the class/instance where it was defined. If there is any potential for re-use, a function is the better choice.
The staticmethod is seldom used, so people reading code that includes one may take a little longer to read it.
alternatives to a static method in Python
To address discuss the advantages of the staticmethod, we need to know what the alternatives are and how they differ from each other.
The staticmethod belongs to a class but cannot access or modify any instance or class information.
There are three alternatives to it:
The classmethod has access to the caller's class.
The instancemethod has access to the caller's instance and its class.
The function has nothing to do with classes. It is the closest in capability to the staticmethod.
Here's what this looks like in code:
# function
# has nothing to do with a class
def make_cat_noise(asker_name):
print('Hi %s, mieets mieets!' % asker_name)
# Yey, we can make cat noises before we've even defined what a cat is!
make_cat_noise('JOey') # just a function
class Cat:
number_of_legs = 4
# special instance method __init__
def __init__(self, name):
self.name = name
# instancemethod
# the instance (e.g. Cat('Kitty')) is passed as the first method argument
def tell_me_about_this_animal(self, asker_name):
print('Hi %s, This cat has %d legs and is called %s'
% (asker_name, self.number_of_legs, self.name))
# classmethod
# the class (e.g. Cat) is passed as the first method argument
# by convention we call that argument cls
#classmethod
def tell_me_about_cats(cls, asker_name):
print("Hi %s, cats have %d legs."
% (asker_name, cls.number_of_legs))
# cls.name # AttributeError because only the instance has .name
# self.name # NameError because self isn't defined in this namespace
# staticmethod
# no information about the class or the instance is passed to the method
#staticmethod
def make_noise(asker_name):
print('Hi %s, meooow!' % asker_name)
# class and instance are not accessible from here
# one more time for fun!
make_cat_noise('JOey') # just a function
# We just need the class to call a classmethod or staticmethod:
Cat.make_noise('JOey') # staticmethod
Cat.tell_me_about_cats('JOey') # classmethod
# Cat.tell_me_about_this_animal('JOey') # instancemethod -> TypeError
# With an instance we can use instancemethod, classmethod or staticmethod
mycat = Cat('Kitty') # mycat is an instance of the class Cat
mycat.make_noise('JOey') # staticmethod
mycat.tell_me_about_cats('JOey') # classmethod
mycat.tell_me_about_this_animal('JOey') # instancemethod
When you call a function object from an object instance, it becomes a 'bound method' and gets the instance object itself is passed in as a first argument.
When you call a classmethod object (which wraps a function object) on an object instance, the class of the instance object gets passed in as a first argument.
When you call a staticmethod object (which wraps a function object), no implicit first argument is used.
class Foo(object):
def bar(*args):
print args
#classmethod
def baaz(*args):
print args
#staticmethod
def quux(*args):
print args
>>> foo = Foo()
>>> Foo.bar(1,2,3)
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 int instance instead)
>>> Foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> Foo.quux(1,2,3)
(1, 2, 3)
>>> foo.bar(1,2,3)
(<Foo object at 0x1004a4510>, 1, 2, 3)
>>> foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> foo.quux(1,2,3)
(1, 2, 3)
static methods are great because you don't have to declare an instance of the object to which the method belongs.
python's site has some great documentation on static methods here:
http://docs.python.org/library/functions.html#staticmethod
In my estimation, there is no single performance benefit of using #staticmethods compared to just defining the function outside of and separate from the class it would otherwise be a #staticmethod of.
The only thing I would say justifies their existence is convenience. Static methods are common in other popular programming languages, so why not python? If you want to create a function with behavior that is very closely associated with the class you are creating it for but it doesn't actually access/modify the internal data of an instance of the class in a way that justifies conceptualizing it as a typical method of that class then slap a #staticmethod above it and anyone reading your code will immediately learn a lot about the nature of the method and its relationship to the class.
One thing I occasionally like to do is place functionality that my class uses internally a lot into private #staticmethods. That way I do not clutter the API exposed by my module with methods that no one using my module would ever need to see let alone use.
Static methods have almost no reason-to-be in Python. You use either instance methods or class methods.
def method(self, args):
self.member = something
#classmethod
def method(cls, args):
cls.member = something
#staticmethod
def method(args):
MyClass.member = something
# The above isn't really working
# if you have a subclass
Because namespacing functions is nice (as was previously pointed out):
When I want to be explicit about methods that don't change the state of the object, I use static methods. This discourages people on my team to start changing the object's attributes in those methods.
When i refactor really rotten code, I start by trying to make as many methods #staticmethod as possible. This allows me then to extract these methods into a class - though I agree, this is rarely something I use, it did came in helpful a few times.

What happens when we edit(append, remove...) a list and can we execute actions each time a list is edited

I would like to know if there is a way to create a list that will execute some actions each time I use the method append(or an other similar method).
I know that I could create a class that inherits from list and overwrite append, remove and all other methods that change content of list but I would like to know if there is an other way.
By comparison, if I want to print 'edited' each time I edit an attribute of an object I will not execute print("edited") in all methods of the class of that object. Instead, I will only overwrite __setattribute__.
I tried to create my own type which inherits of list and overwrite __setattribute__ but that doesn't work. When I use myList.append __setattribute__ isn't called. I would like to know what's realy occured when I use myList.append ? Is there some magic methods called that I could overwrite ?
I know that the question have already been asked there : What happens when you call `append` on a list?. The answer given is just, there is no answer... I hope it's a mistake.
I don't know if there is an answer to my request so I will also explain you why I'm confronted to that problem. Maybe I can search in an other direction to do what I want. I have got a class with several attributes. When an attribute is edited, I want to execute some actions. Like I explain before, to do this I am use to overwrite __setattribute__. That works fine for most of attributes. The problem is lists. If the attribute is used like this : myClass.myListAttr.append(something), __setattribute__ isn't called while the value of the attribute have changed.
The problem would be the same with dictionaries. Methods like pop doesn't call __setattribute__.
If I understand correctly, you would want something like Notify_list that would call some method (argument to the constructor in my implementation) every time a mutating method is called, so you could do something like this:
class Test:
def __init__(self):
self.list = Notify_list(self.list_changed)
def list_changed(self,method):
print("self.list.{} was called!".format(method))
>>> x = Test()
>>> x.list.append(5)
self.list.append was called!
>>> x.list.extend([1,2,3,4])
self.list.extend was called!
>>> x.list[1] = 6
self.list.__setitem__ was called!
>>> x.list
[5, 6, 2, 3, 4]
The most simple implementation of this would be to create a subclass and override every mutating method:
class Notifying_list(list):
__slots__ = ("notify",)
def __init__(self,notifying_method, *args,**kw):
self.notify = notifying_method
list.__init__(self,*args,**kw)
def append(self,*args,**kw):
self.notify("append")
return list.append(self,*args,**kw)
#etc.
This is obviously not very practical, writing the entire definition would be very tedious and very repetitive, so we can create the new subclass dynamically for any given class with functions like the following:
import functools
import types
def notify_wrapper(name,method):
"""wraps a method to call self.notify(name) when called
used by notifying_type"""
#functools.wraps(method)
def wrapper(*args,**kw):
self = args[0]
# use object.__getattribute__ instead of self.notify in
# case __getattribute__ is one of the notifying methods
# in which case self.notify will raise a RecursionError
notify = object.__getattribute__(self, "_Notify__notify")
# I'd think knowing which method was called would be useful
# you may want to change the arguments to the notify method
notify(name)
return method(*args,**kw)
return wrapper
def notifying_type(cls, notifying_methods="all"):
"""creates a subclass of cls that adds an extra function call when calling certain methods
The constructor of the subclass will take a callable as the first argument
and arguments for the original class constructor after that.
The callable will be called every time any of the methods specified in notifying_methods
is called on the object, it is passed the name of the method as the only argument
if notifying_methods is left to the special value 'all' then this uses the function
get_all_possible_method_names to create wrappers for nearly all methods."""
if notifying_methods == "all":
notifying_methods = get_all_possible_method_names(cls)
def init_for_new_cls(self,notify_method,*args,**kw):
self._Notify__notify = notify_method
namespace = {"__init__":init_for_new_cls,
"__slots__":("_Notify__notify",)}
for name in notifying_methods:
method = getattr(cls,name) #if this raises an error then you are trying to wrap a method that doesn't exist
namespace[name] = notify_wrapper(name, method)
# I figured using the type() constructor was easier then using a meta class.
return type("Notify_"+cls.__name__, (cls,), namespace)
unbound_method_or_descriptor = ( types.FunctionType,
type(list.append), #method_descriptor, not in types
type(list.__add__),#method_wrapper, also not in types
)
def get_all_possible_method_names(cls):
"""generates the names of nearly all methods the given class defines
three methods are blacklisted: __init__, __new__, and __getattribute__ for these reasons:
__init__ conflicts with the one defined in notifying_type
__new__ will not be called with a initialized instance, so there will not be a notify method to use
__getattribute__ is fine to override, just really annoying in most cases.
Note that this function may not work correctly in all cases
it was only tested with very simple classes and the builtin list."""
blacklist = ("__init__","__new__","__getattribute__")
for name,attr in vars(cls).items():
if (name not in blacklist and
isinstance(attr, unbound_method_or_descriptor)):
yield name
Once we can use notifying_type creating Notify_list or Notify_dict would be as simple as:
import collections
mutating_list_methods = set(dir(collections.MutableSequence)) - set(dir(collections.Sequence))
Notify_list = notifying_type(list, mutating_list_methods)
mutating_dict_methods = set(dir(collections.MutableMapping)) - set(dir(collections.Mapping))
Notify_dict = notifying_type(dict, mutating_dict_methods)
I have not tested this extensively and it quite possibly contains bugs / unhandled corner cases but I do know it worked correctly with list!

When should I use #classmethod and when def method(self)?

While integrating a Django app I have not used before, I found two different ways to define functions inside the class. The author seems to use them both distinctively and intentionally. The first one is the one that I myself use a lot:
class Dummy(object):
def some_function(self, *args, **kwargs):
# do something here
# self is the class instance
The other one is the one I never use, mostly because I do not understand when and what to use it for:
class Dummy(object):
#classmethod
def some_function(cls, *args, **kwargs):
# do something here
# cls refers to what?
The classmethod decorator in the python documentation says:
A class method receives the class as the implicit first argument, just
like an instance method receives the instance.
So I guess cls refers to Dummy itself (the class, not the instance). I do not exactly understand why this exists, because I could always do this:
type(self).do_something_with_the_class
Is this just for the sake of clarity, or did I miss the most important part: spooky and fascinating things that couldn't be done without it?
Your guess is correct - you understand how classmethods work.
The why is that these methods can be called both on an instance OR on the class (in both cases, the class object will be passed as the first argument):
class Dummy(object):
#classmethod
def some_function(cls,*args,**kwargs):
print cls
#both of these will have exactly the same effect
Dummy.some_function()
Dummy().some_function()
On the use of these on instances: There are at least two main uses for calling a classmethod on an instance:
self.some_function() will call the version of some_function on the actual type of self, rather than the class in which that call happens to appear (and won't need attention if the class is renamed); and
In cases where some_function is necessary to implement some protocol, but is useful to call on the class object alone.
The difference with staticmethod: There is another way of defining methods that don't access instance data, called staticmethod. That creates a method which does not receive an implicit first argument at all; accordingly it won't be passed any information about the instance or class on which it was called.
In [6]: class Foo(object): some_static = staticmethod(lambda x: x+1)
In [7]: Foo.some_static(1)
Out[7]: 2
In [8]: Foo().some_static(1)
Out[8]: 2
In [9]: class Bar(Foo): some_static = staticmethod(lambda x: x*2)
In [10]: Bar.some_static(1)
Out[10]: 2
In [11]: Bar().some_static(1)
Out[11]: 2
The main use I've found for it is to adapt an existing function (which doesn't expect to receive a self) to be a method on a class (or object).
One of the most common uses of classmethod in Python is factories, which are one of the most efficient methods to build an object. Because classmethods, like staticmethods, do not need the construction of a class instance. (But then if we use staticmethod, we would have to hardcode the instance class name in the function)
This blog does a great job of explaining it:
https://iscinumpy.gitlab.io/post/factory-classmethods-in-python/
If you add decorator #classmethod, That means you are going to make that method as static method of java or C++. ( static method is a general term I guess ;) )
Python also has #staticmethod. and difference between classmethod and staticmethod is whether you can
access to class or static variable using argument or classname itself.
class TestMethod(object):
cls_var = 1
#classmethod
def class_method(cls):
cls.cls_var += 1
print cls.cls_var
#staticmethod
def static_method():
TestMethod.cls_var += 1
print TestMethod.cls_var
#call each method from class itself.
TestMethod.class_method()
TestMethod.static_method()
#construct instances
testMethodInst1 = TestMethod()
testMethodInst2 = TestMethod()
#call each method from instances
testMethodInst1.class_method()
testMethodInst2.static_method()
all those classes increase cls.cls_var by 1 and print it.
And every classes using same name on same scope or instances constructed with these class is going to share those methods.
There's only one TestMethod.cls_var
and also there's only one TestMethod.class_method() , TestMethod.static_method()
And important question. why these method would be needed.
classmethod or staticmethod is useful when you make that class as a factory
or when you have to initialize your class only once. like open file once, and using feed method to read the file line by line.

What is the purpose of static methods? How do I know when to use one? [duplicate]

This question already has answers here:
Difference between #staticmethod and #classmethod
(35 answers)
Why do we use #staticmethod?
(4 answers)
Closed last month.
I ran into unbound method error in python with this code:
import random
class Sample(object):
def drawSample(samplesize, List):
sample = random.sample(List, samplesize)
return sample
Choices=range(100)
print(Sample.drawSample(5, Choices))
I was able to fix the problem by adding #staticmethod to the method. However, I don't really understand the situation.
What is the point of using "static" methods? Why does it solve the problem in this code, and why are they ever necessary? Conversely, why would I ever not want to do it (i.e., why is extra code needed to make the method static)?
See this article for detailed explanation.
TL;DR
1.It eliminates the use of self argument.
2.It reduces memory usage because Python doesn't have to instantiate a bound-method for each object instiantiated:
>>>RandomClass().regular_method is RandomClass().regular_method
False
>>>RandomClass().static_method is RandomClass().static_method
True
>>>RandomClass.static_method is RandomClass().static_method
True
3.It improves code readability, signifying that the method does not depend on state of the object itself.
4.It allows for method overriding in that if the method were defined at the module-level (i.e. outside the class) a subclass would not be able to override that method.
Static methods have limited use, because they don't have access to the attributes of an instance of a class (like a regular method does), and they don't have access to the attributes of the class itself (like a class method does).
So they aren't useful for day-to-day methods.
However, they can be useful to group some utility function together with a class - e.g. a simple conversion from one type to another - that doesn't need access to any information apart from the parameters provided (and perhaps some attributes global to the module.)
They could be put outside the class, but grouping them inside the class may make sense where they are only applicable there.
You can also reference the method via an instance or the class, rather than the module name, which may help the reader understand to what instance the method is related.
This is not quite to the point of your actual question, but since you've said you are a python newbie perhaps it will be helpful, and no one else has quite come out and said it explicitly.
I would never have fixed the above code by making the method a static method. I would either have ditched the class and just written a function:
def drawSample(samplesize,List):
sample=random.sample(List,samplesize)
return sample
Choices=range(100)
print drawSample(5,Choices)
If you have many related functions, you can group them in a module - i.e, put them all in the same file, named sample.py for example; then
import sample
Choices=range(100)
print sample.drawSample(5,Choices)
Or I would have added an __init__ method to the class and created an instance that had useful methods:
class Sample(object):
'''This class defines various methods related to the sample'''
def __init__(self, thelist):
self.list = thelist
def draw_sample(self, samplesize):
sample=random.sample(self.list,samplesize)
return sample
choices=Sample(range(100))
print choices.draw_sample(5)
(I also changed the case conventions in the above example to match the style recommended by PEP 8.)
One of the advantages of Python is that it doesn't force you to use classes for everything. You can use them only when there is data or state that should be associated with the methods, which is what classes are for. Otherwise you can use functions, which is what functions are for.
Why one would want to define static methods?
Suppose we have a class called Math then
nobody will want to create object of class Math
and then invoke methods like ceil and floor and fabs on it.
So we make them static.
For example doing
>> Math.floor(3.14)
is much better than
>> mymath = Math()
>> mymath.floor(3.14)
So they are useful in some way. You need not create an instance of a class to use them.
Why are not all methods defined as static methods?
They don't have access to instance variables.
class Foo(object):
def __init__(self):
self.bar = 'bar'
def too(self):
print self.bar
#staticmethod
def foo():
print self.bar
Foo().too() # works
Foo.foo() # doesn't work
That is why we don't make all the methods static.
The alternatives to a staticmethod are: classmethod, instancemethod, and function. If you don't know what these are, scroll down to the last section. If a staticmethod is better than any of these alternatives, depends on for what purpose it is written.
advantages of the Python static method
If you don't need access to the attributes or methods of the class or instance, a staticmethod is better than a classmethod or instancemethod. That way it is clear (from the #staticmethod decorator) that the class' and instance's state is not read or modified. However, using a function makes that distinction even clearer (see disadvantages).
The call signature of a staticmethod is the same as that of a classmethod or instancemethod, namely <instance>.<method>(<arguments>). Hence it can easily be replaced by one of the three if that is needed later on or in a derived class. You can't do that with a simple function.
A staticmethod can be used instead of a function to make clear that it subjectively belongs to a class and to prevent namespace conflicts.
disadvantages of the Python static method
It cannot access attributes or methods of the instance or class.
The call signature of a staticmethod is the same as that of a classmethod or instancemethod. This masks the fact that the staticmethod does not actually read or modify any object information. This makes code harder to read. Why not just use a function?
A staticmethod is difficult to re-use if you ever need to call it from outside the class/instance where it was defined. If there is any potential for re-use, a function is the better choice.
The staticmethod is seldom used, so people reading code that includes one may take a little longer to read it.
alternatives to a static method in Python
To address discuss the advantages of the staticmethod, we need to know what the alternatives are and how they differ from each other.
The staticmethod belongs to a class but cannot access or modify any instance or class information.
There are three alternatives to it:
The classmethod has access to the caller's class.
The instancemethod has access to the caller's instance and its class.
The function has nothing to do with classes. It is the closest in capability to the staticmethod.
Here's what this looks like in code:
# function
# has nothing to do with a class
def make_cat_noise(asker_name):
print('Hi %s, mieets mieets!' % asker_name)
# Yey, we can make cat noises before we've even defined what a cat is!
make_cat_noise('JOey') # just a function
class Cat:
number_of_legs = 4
# special instance method __init__
def __init__(self, name):
self.name = name
# instancemethod
# the instance (e.g. Cat('Kitty')) is passed as the first method argument
def tell_me_about_this_animal(self, asker_name):
print('Hi %s, This cat has %d legs and is called %s'
% (asker_name, self.number_of_legs, self.name))
# classmethod
# the class (e.g. Cat) is passed as the first method argument
# by convention we call that argument cls
#classmethod
def tell_me_about_cats(cls, asker_name):
print("Hi %s, cats have %d legs."
% (asker_name, cls.number_of_legs))
# cls.name # AttributeError because only the instance has .name
# self.name # NameError because self isn't defined in this namespace
# staticmethod
# no information about the class or the instance is passed to the method
#staticmethod
def make_noise(asker_name):
print('Hi %s, meooow!' % asker_name)
# class and instance are not accessible from here
# one more time for fun!
make_cat_noise('JOey') # just a function
# We just need the class to call a classmethod or staticmethod:
Cat.make_noise('JOey') # staticmethod
Cat.tell_me_about_cats('JOey') # classmethod
# Cat.tell_me_about_this_animal('JOey') # instancemethod -> TypeError
# With an instance we can use instancemethod, classmethod or staticmethod
mycat = Cat('Kitty') # mycat is an instance of the class Cat
mycat.make_noise('JOey') # staticmethod
mycat.tell_me_about_cats('JOey') # classmethod
mycat.tell_me_about_this_animal('JOey') # instancemethod
When you call a function object from an object instance, it becomes a 'bound method' and gets the instance object itself is passed in as a first argument.
When you call a classmethod object (which wraps a function object) on an object instance, the class of the instance object gets passed in as a first argument.
When you call a staticmethod object (which wraps a function object), no implicit first argument is used.
class Foo(object):
def bar(*args):
print args
#classmethod
def baaz(*args):
print args
#staticmethod
def quux(*args):
print args
>>> foo = Foo()
>>> Foo.bar(1,2,3)
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 int instance instead)
>>> Foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> Foo.quux(1,2,3)
(1, 2, 3)
>>> foo.bar(1,2,3)
(<Foo object at 0x1004a4510>, 1, 2, 3)
>>> foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> foo.quux(1,2,3)
(1, 2, 3)
static methods are great because you don't have to declare an instance of the object to which the method belongs.
python's site has some great documentation on static methods here:
http://docs.python.org/library/functions.html#staticmethod
In my estimation, there is no single performance benefit of using #staticmethods compared to just defining the function outside of and separate from the class it would otherwise be a #staticmethod of.
The only thing I would say justifies their existence is convenience. Static methods are common in other popular programming languages, so why not python? If you want to create a function with behavior that is very closely associated with the class you are creating it for but it doesn't actually access/modify the internal data of an instance of the class in a way that justifies conceptualizing it as a typical method of that class then slap a #staticmethod above it and anyone reading your code will immediately learn a lot about the nature of the method and its relationship to the class.
One thing I occasionally like to do is place functionality that my class uses internally a lot into private #staticmethods. That way I do not clutter the API exposed by my module with methods that no one using my module would ever need to see let alone use.
Static methods have almost no reason-to-be in Python. You use either instance methods or class methods.
def method(self, args):
self.member = something
#classmethod
def method(cls, args):
cls.member = something
#staticmethod
def method(args):
MyClass.member = something
# The above isn't really working
# if you have a subclass
Because namespacing functions is nice (as was previously pointed out):
When I want to be explicit about methods that don't change the state of the object, I use static methods. This discourages people on my team to start changing the object's attributes in those methods.
When i refactor really rotten code, I start by trying to make as many methods #staticmethod as possible. This allows me then to extract these methods into a class - though I agree, this is rarely something I use, it did came in helpful a few times.

Categories

Resources