I understood that staticmethod should always be referred to by the classname in which they belong. But I see that they can also be accessed by the keyword self too.
This is bit confusing and I don't see interpreter throwing an error.
import unittest
class TestA(unittest.TestCase):
#staticmethod
def fun1():
return True
#staticmethod
def fun2():
return False
def test_one(self):
assert TestA.fun1() == True
def test_two(self):
assert self.fun2() == False
if __name__ == '__main__':
unittest.main()
What is the right way to access the staticmethod. Like TestA.fun1 above which is clear to me or as self.fun2 which is mildly concerning because there is no instance sent to fun2.
Either way is acceptable, as described in the documentation:
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.
In some sense, the point of a staticmethod is to allow you to call the method without worrying about whether you're calling it on an instance or a class.
Either way "works", but if possible you should call using the instance. This allows it to work properly in the event that you subclass TestA. That is, it will properly find the implementation of the static method for the type of 'self' rather than the hard coded TestA. If you were in a context where you had a "cls" variable (such as a class method or perhaps factory function) you should call on that. You would only name the class object directly if you always want to call the TestA implementation, typically when you don't have a self or cls reference in the local scope.
Related
Classes, methods, and instances have me thoroughly confused. Why is it that this works:
class Computer:
def config(self):
print('i5, 16gb, 1TB')
com1 = Computer()
com1.config()
But this does not?:
class Computer:
def config(self):
print('i5, 16gb, 1TB')
com1 = Computer()
Computer.config()
But, if you modify the code directly above to include the instance as an argument when calling the method, like so:
Computer.config(com1)
it works? I see the difference between the two, but I don't understand it.
In your example Computer.config is an instance method, means it is bound to an object, or in other words requires an object. Therefore in your second example you would write:
com1.config()
You can also write it in the following style:
Computer.config(com1)
which is the same and just syntactic sugar. In same special cases you might prefer the latter one, e.g. when duck typing is required, but the first one is definitely the preferred way.
In addition, there are staticmethod or classmethod functions, which don't require any objects. An example would be this:
class Computer
#staticmethod
def config():
print("Foo")
Computer.config() # no object required at all, because its a staticmethod
Please notice the missing self reference. Technically Computer.config as a staticmethod is just a simple function, but it helps to group functionalities so to make them a class member.
This is because config() is an instance method, and not a static method. An instance method, simply said, is shared across all objects of a class, and cannot be accessed by just using the class name. If you want to call config() by just using class name, you have to tell compiler that it is static. To do this use #staticmethod tag, and remove the self argument:
class Computer:
#staticmethod
def config():
print('i5, 16gb, 1TB')
com1 = Computer()
com1.config()
And as you said:
if you modify the code directly above to include the instance as an
argument when calling the method, like so:
This is because, every instance function takes self as it's first argument. Basically self is somewhat similar to this in C++ or Java, and it tells which object to work upon, i.e., self acts as a pointer to the current object. When you passed the com1 object to the argument, it took self for com1.
That means that when you invoke com1.config() what you are actually doing is calling config with com1 as its argument. So com1.config(() is the same as Computer.config(com1).
Why doesn't the second approach work?
Because Computer is an instance of something called a meta-class. It is somewhat the class definition and not actually an instance of Computer. com1 is an instance created by Computer. You can use com1 to invoke its non-static functions but you can't use the meta-class Computer to invoke non-static functions, which need an object to be ran on.
Why does the third approach work?
Have you noticed the self in the definition of the config function? That means that when you invoke com1.config() what you are actually doing is calling config with com1 as its argument. So com1.config() is the same as Computer.config(com1).
I thought that the following code would result in an error because as far as I have read, a method in a Python class must either have "self" (or any other label, but "self" by convention) as its first argument, or "cls" or similar if the #classmethod decorator is used, or none if the #staticmethod decorator is used.
How come I get no error running this with Python 3.5 in the Terminal, even though test_method does not meet these requirements? It seems to work fine as a static method, but without the decorator.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
class MyClass:
def test_method(args):
print(args[1])
#staticmethod
def static_method():
print("static_method")
#classmethod
def class_method(cls):
print("class_method")
def main(args):
MyClass.test_method(args)
if __name__ == '__main__':
sys.exit(main(sys.argv))
Output:
$ python3 testscript.py "testing"
$ testing
EDIT:
My question could also be phrased differently, drawing attention away from self and to #staticmethod: "How come I'm getting a seemingly working static method without the #staticmethod decorator?"
In Python 2, functions defined in a class body are automatically converted to "unbound methods", and cannot be called directly without a staticmethod decorator. In Python 3, this concept was removed; MyClass.text_method is a simple function that lives inside the MyClass namespace, and can be called directly.
The main reason to still use staticmethod in Python 3 is if you also want to call the method on an instance. If you don't use the decorator, the method will always be passed the instance as the first parameter, causing a TypeError.
There is nothing special about this. In python 3 there is no difference between a function defined inside a class or a function defined outside a class. Both of them are normal functions.
The self that you are talking about here or maybe cls comes into picture only when you access the function through an instance. Hence here you didn't get any error.
However if you modify your code just a little bit to look like the following, then you'd get an error that you expected.
def main(args):
MyClass().test_method(args)
# Should throw an error
EDIT:
#staticmethod will work on both class instances like MyClass().test_method(args)and just a regular direct call like MyClass.test_method(args)
However a regular method(without self in it) can't be called on a class instance. So you will always have to call it as MyClass.test_method(args)
self isn't necessarily required. However, if you want to reference any variable or value that is associated with the object(instantiation of the class) (E.g. for a class about cars, it's speed, self.speed) you'll need to have self as a parameter in the function. For this reason, it's common practice to always have self as an argument, otherwise you aren't really using the class for the right reason.
EDIT:
This will actually throw an error if you do the following:
class a():
def __init__(self, x):
self.asd = x
def hello(x):
print(x)
>>> g = a(4)
>>> g.hello(5)
as when calling "hello", both "self" and "4" will be passed as parameters. It would work in the following instance, which is what I was saying above:
>>> g = a
>>> g.hello(4)
or
>>> a.hello(4)
To add on to the existing answers here and provide a code example:
class MyClass:
def __init__(self):
pass
def myStaticMethod():
print("a static method")
#staticmethod
def myStaticMethodWithArg(my_arg):
print(my_arg)
print("a static method")
MyClass.myStaticMethod()
MyClass.myStaticMethodWithArg("skhsdkj")
abc = MyClass()
abc.myStaticMethodWithArg("avc")
Try removing the #staticmethod decorator and rerunning the code and see what happens! (The very last call will fail since the method is passed in both self and the string input. By adding the decorator, we can guide the interpreter to perform our desired action)
If I have the following class.
class Foo:
#staticmethod
def _bar():
# do something
print "static method"
def instancemethod(self):
Foo._bar() # method 1
self._bar() # method 2
In this case, is method 1 a preferred way of calling staticmethod _bar() or method 2 in the Python world?
Write the code that expresses what you want to do. If you want to call this method right here:
class Foo:
#staticmethod
def _bar(): # <-- this one
# do something
print "static method"
then specify that particular method:
Foo._bar()
If you want to call whatever self._bar resolves to, meaning you've actually decided that it makes sense to override it and made sure your code still behaves sensibly when that method is overridden, then specify self._bar:
self._bar()
Most likely, this method isn't designed to be overridden, and the code that uses it isn't designed to anticipate overriding it, so you probably want Foo._bar().
I am trying to use a nose_parameterized test and want to use it for a unittest method.
from nose.tools import assert_equal
from nose_parameterized import parameterized
import unittest
Class TestFoo(unittest.TestCase):
def setUp(self):
self.user1 = "Bar"
self.user2 = "Foo"
#parameterized.expand([
("testuser1",self.user1,"Bar"),
("testuser2",self.user2,"Foo")
]
def test_param(self,name,input,expected):
assert_equal(input,expected)
But self is not defined in the decorator function. Is there a workaround for this? I know that I can use global class variables but I need to use variables in setUp.
One workaround would be to use a string containing the attribute name in the decorator, and getattr in the test function:
#parameterized.expand([
("testuser1", "user1", "Bar"),
("testuser2", "user2", "Foo")
])
def test_param(self, name, input, expected):
assert_equal(getattr(self, input), expected)
With this approach, test_param assumes that the value of its input argument is the attribute name whose value should be checked against expected.
The decorator is not run when you seem to assume it will be run. In the following example:
class spam:
#eggs
def beans( self ):
pass
remember that the use of the decorator is the same as saying:
beans = eggs( beans )
inside the spam scope, immediately after the def statement itself is executed. When is a def statement executed? At the time the class and its methods are defined. The decorator modifies the class-level definition of the method spam.beans, not the instance-level value of self.beans. And of course, this occurs long before any instances of that class are ever created, i.e. before a reference to any one particular instance, self, is ever meaningful.
If you want to attach a particular callable (e.g. a modified test_param callable that has certain arguments pre-baked into it using functools.partial) to an instance self, you can of course do so inside one of the instance methods (e.g. __init__ or setUp).
Some people will describe the class-definition code as happening at "parse time" and instance-level code as happening at "run time". You may or may not find that a helpful way of thinking about it, although really almost everything is "run-time" in Python.
I'm trying to get the name of all methods in my class.
When testing how the inspect module works, i extraced one of my methods by obj = MyClass.__dict__['mymethodname'].
But now inspect.ismethod(obj) returns False while inspect.isfunction(obj) returns True, and i don't understand why. Is there some strange way of marking methods as methods that i am not aware of? I thought it was just that it is defined in the class and takes self as its first argument.
You are seeing some effects of the behind-the-scenes machinery of Python.
When you write f = MyClass.__dict__['mymethodname'], you get the raw implementation of "mymethodname", which is a plain function. To call it, you need to pass in an additional parameter, class instance.
When you write f = MyClass.mymethodname (note the absence of parentheses after mymethodname), you get an unbound method of class MyClass, which is an instance of MethodType that wraps the raw function you obtained above. To call it, you need to pass in an additional parameter, class instance.
When you write f = MyClass().mymethodname (note that i've created an object of class MyClass before taking its method), you get a bound method of an instance of class MyClass. You do not need to pass an additional class instance to it, since it's already stored inside it.
To get wrapped method (bound or unbound) by its name given as a string, use getattr, as noted by gnibbler. For example:
unbound_mth = getattr(MyClass, "mymethodname")
or
bound_mth = getattr(an_instance_of_MyClass, "mymethodname")
Use the source
def ismethod(object):
"""Return true if the object is an instance method.
Instance method objects provide these attributes:
__doc__ documentation string
__name__ name with which this method was defined
__func__ function object containing implementation of method
__self__ instance to which this method is bound"""
return isinstance(object, types.MethodType)
The first argument being self is just by convention. By accessing the method by name from the class's dict, you are bypassing the binding, so it appears to be a function rather than a method
If you want to access the method by name use
getattr(MyClass, 'mymethodname')
Well, do you mean that obj.mymethod is a method (with implicitly passed self) while Klass.__dict__['mymethod'] is a function?
Basically Klass.__dict__['mymethod'] is the "raw" function, which can be turned to a method by something called descriptors. This means that every function on a class can be both a normal function and a method, depending on how you access them. This is how the class system works in Python and quite normal.
If you want methods, you can't go though __dict__ (which you never should anyways). To get all methods you should do inspect.getmembers(Klass_or_Instance, inspect.ismethod)
You can read the details here, the explanation about this is under "User-defined methods".
From a comment made on #THC4k's answer, it looks like the OP wants to discriminate between built-in methods and methods defined in pure Python code. User defined methods are of types.MethodType, but built-in methods are not.
You can get the various types like so:
import inspect
import types
is_user_defined_method = inspect.ismethod
def is_builtin_method(arg):
return isinstance(arg, (type(str.find), type('foo'.find)))
def is_user_or_builtin_method(arg):
MethodType = types.MethodType
return isinstance(arg, (type(str.find), type('foo'.find), MethodType))
class MyDict(dict):
def puddle(self): pass
for obj in (MyDict, MyDict()):
for test_func in (is_user_defined_method, is_builtin_method,
is_user_or_builtin_method):
print [attr
for attr in dir(obj)
if test_func(getattr(obj, attr)) and attr.startswith('p')]
which prints:
['puddle']
['pop', 'popitem']
['pop', 'popitem', 'puddle']
['puddle']
['pop', 'popitem']
['pop', 'popitem', 'puddle']
You could use dir to get the name of available methods/attributes/etc, then iterate through them to see which ones are methods. Like this:
[ mthd for mthd in dir(FooClass) if inspect.ismethod(myFooInstance.__getattribute__(mthd)) ]
I'm expecting there to be a cleaner solution, but this could be something you could use if nobody else comes up with one. I'd like if I didn't have to use an instance of the class to use getattribute.