Calling an instance method within a static method in Python - python

Lets say I have class with a static and instance method. How would I go about calling the instance method from my static method:
I wouldn't be able to use self in the static method. So, would it look something like this?
class Example():
def instance_method(self):
pass
#staticmethod
def static_method():
instance_method()

Calling a non-static method in a class requires that an object exists of that class, and that you have a reference to that object. You could have 100s of instances of the same class, all of which could behave differently when one of that class's instance methods is called on them. Until you create an instance of the class, there's no way to call an instance method (hence the name).
Here's a trivial answer to your question, which is to create an instance of the class just so you can call the method you're interested in calling:
class Example():
def instance_method(self):
print("I'm an instance method!")
#staticmethod
def static_method():
instance = Example()
instance.instance_method()
Example.static_method()
Result:
I'm an instance method!

Related

Python: calling class variables and class methods from within __init__ function

I am trying to gain a better understanding of class variables and the #classmethod decorator in python. I've done a lot of googling but I am having difficulty grasping basic OOP concepts. Take the following class:
class Repository:
repositories = []
repository_count = 0
def __init__(self):
self.update_repositories()
Repository.repository_count += 1
#classmethod
def update_repositories(cls):
if not cls.repositories:
print('appending repository')
cls.repositories.append('twenty')
else:
print('list is full')
a = Repository()
b = Repository()
print(Repository.repository_count)
Output:
appending repository
list is full
2
In the __init__ method, why does self.update_repositories() successfully call the update_repositories class method? I thought that self in this case refers to the instantiated object, not the class?
The code works without using the #classmethod decorator. Why?
In the __init__ method why do I need to use the keyword Repository in Repository.repository_count += 1? Am I doing this correctly or is there a better practice?
Class methods can be called from an instance. Look at the documentation here.
A class method 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. If a class method is called for a derived class, the derived class object is passed as the implied first argument.
The function works without the decorator, but it is not a class method. The cls and self parameter names are simply convention. You can put anything in the place of cls or self. For example:
class Demo:
def __init__(self):
pass
def instance_method(test):
print(test)
#classmethod
def class_method(test):
print(test)
demo = Demo()
This results in:
demo.instance_method()
>>> <__main__.Demo object at 0x7facd8e34510>
demo.class_method()
>>> <class '__main__.Demo'>
So all non decorated methods in a class are a considered instance
methods and all methods decorated with #classmethod are
class methods. Naming your parameters cls, self or
anything else for that matter does not effect the functionality, but I
would strongly advice sticking with convention.
In your case specifcally removing the #classmethod decorator turns the method into an instance method and cls is now actually what self would normally be, a reference to the class's instance. Since class methods and attributes can be called from an instance cls.update_repositories still points to the class variable.
Depends on what you are trying to do. Generally if you want to access a class variable or method inside a class, but outside a class method, your approach is correct.

How to call a method from base class a few levels up in the inheritance chain?

Assume we have following inheritance chain:
class Base:
def method(self):
# …
class Derived1(Base):
def method(self):
# …
class Derived2(Derived1):
pass
class Derived3(Derived2):
def method(self):
# …
The problem: I would like to somehow define method in Derived3 so that it calls itself from Base.
Normally I would just write:
class Derived3(Derived2):
super().method()
But this would call method from Derived1, which is exactly what I want to avoid. I want to call method from Base.
The simplest approach is to call the Base method directly, passing self explicitly:
Base.method(self)
If the goal is to skip to "whatever is after some known bad super class in the MRO" though, you can use super with explicit arguments to act as if it was called from the "bad super class" so it moves to "whatever comes next":
class Derived3(Derived2):
def method(self):
# Call method from next class after Derived1 in MRO, which happens to be Base
# Using super means the method is bound, so self passed implicitly to method
super(Derived1, self).method()
You can explicitly call a member of the superclass, simply passing self as the first argument:
Base.method(self)
Complete example:
class Derived3(Derived2):
def method(self):
Base.method(self)
This will execute Base.method on the instance specified by self, which is passed to Derived3.method automatically when it is accessed through an instance.

Python refer to class from within class

I've become aware of #staticmethod - next question, are you supposed to use the class name to refer to these methods from within the class?
class C:
#staticmethod
def imstatic():
print("i'm static")
#staticmethod
def anotherstatic():
# Is this the proper python way?
C.imstatic()
#staticmethod
def brokenstatic():
# This doesn't work..
self.imstatic()
Yes, as you don't have any other reference to the class from within a static method. You could make these class methods instead, using the classmethod decorator:
class C:
#staticmethod
def imstatic():
print("i'm static")
#classmethod
def anotherstatic(cls):
cls.imstatic()
A class method does have a reference to the class.
If you need to refer to the class within a static method you should probably be using a classmethod instead:
class C:
#staticmethod
def imstatic():
print("i'm static")
#classmethod
def imclass(cls):
cls.imstatic()
In the same way that instance methods are "magically" given a reference to the instance as the first argument, class methods are given a reference to the class. You can call them either from an instance or from the class directly, for example both of the following are valid and have the same behavior:
C().imclass()
C.imclass()
That being said, if you do still want to use a static method your current approach is correct, just refer to the class by name.
If you always want to call the static method of that specific class, yes, you must specify it by name. If you want to support overriding the static methods, what you want is a classmethod instead: it passes the class on which the method is being called as the first parameter, analogous to self on regular instance methods, so you can call the overridden method. In general I'd suggest using classmethods.

How to call internal functions inside the constructor class?

Hello i have this code
class Test(object):
def start_conn(self):
pass
def __init__(self):
self.conn = start_conn()
But this code make this error:
NameError: global name 'start_conn' is not defined
If i write self.conn = self.start_conn() the program works without error, my question is, is a must to call with self the methods of the class when i'm creating a new instance? or is a desgin error from my side?
Thanks a lot
In short, it's a must. You have to refer to the container in which the methods are stored. Most of the time that means referring to self.
The way this works is as follows. When you define a (new-style) class
class FooClass(object):
def my_method(self, arg):
print self.my_method, arg
you create a type object that contains the method in its unbound state. You can then refer to that unbound method via the name of the class (i.e. via FooClass.my_method); but to use the method, you have to explicitly pass a FooClass object via the self parameter (as in FooClass.my_method(fooclass_instance, arg)).
Then, when you instantiate your class (f = FooClass()), the methods of FooClass are bound to the particular instance f. self in each of the methods then refers to that instance (f); this is automatic, so you no longer have to pass f into the method explicitly. But you could still do FooClass.my_method(f, arg); that would be equivalent to f.my_method(arg).
Note, however, that in both cases, self is the container through which the other methods of the class are passed to my_method, which doesn't have access to them through any other avenue.

What is the Python equivalent of a Ruby class method?

In ruby you can do this:
class A
def self.a
'A.a'
end
end
puts A.a #-> A.a
How can this be done in python. I need a method of a class to be called without it being called on an instance of the class. When I try to do this I get this error:
unbound method METHOD must be called with CLASS instance as first argument (got nothing instead)
This is what I tried:
class A
def a():
return 'A.a'
print A.a()
What you're looking for is the staticmethod decorator, which can be used to make methods that don't require a first implicit argument. It can be used like this:
class A(object):
#staticmethod
def a():
return 'A.a'
On the other hand, if you wish to access the class (not the instance) from the method, you can use the classmethod decorator, which is used mostly the same way:
class A(object):
#classmethod
def a(cls):
return '%s.a' % cls.__name__
Which can still be called without instanciating the object (A.a()).
There are two ways to do this:
#staticmethod
def foo(): # No implicit parameter
print 'foo'
#classmethod
def foo(cls): # Class as implicit paramter
print cls
The difference is that a static method has no implicit parameters at all. A class method receives the class that it is called on in exactly the same way that a normal method receives the instance.
Which one you use depends on if you want the method to have access to the class or not.
Either one can be called without an instance.
You can also access the class object in a static method using __class__:
class A() :
#staticmethod
def a() :
return '{}.a'.format( __class__.__name__ )
At least this works in Python 3.1

Categories

Resources