Could someone explain what is the difference between the following class definitions derived from BaseClass and in what cases it would matter how they are defined:
class BaseClass(object):
def __init__(self):
# ...
def as_dict(self):
# ...
class SomeClass(BaseClass):
def as_dict(self):
# Does this somehow change the method compared to 'AnotherClass.as_dict()' below
return super(SomeClass, self).as_dict()
class AnotherClass(BaseClass): pass
SomeOtherClass = BaseClass
Since you add an as_dict method to SomeClass that contains a single super call, there's no difference in the end behavior for that class. There's a difference in the fact that, overall, you've added a couple more function calls that are not necessary.
AnotherClass behaves just like SomeClass since SomeClass doesn't do anything different in as_dict. It inherits the methods of BaseClass as usual.
SomeOtherClass is simply another name for BaseClass, you aren't creating a subclassing relationship there, just attaching another name by which you can refer to that class.
This is using BaseClass with a different name.
class AnotherClass(BaseClass): pass
This is using BaseClass but modifying the method "as_dict". Inside the as_dict method, you can do anything (ie.modify the parameters sent to this method) then run the usual function of the as_dict method with super(SomeClass, self).as_dict()
class SomeClass(BaseClass):
def as_dict(self):
# Does this somehow change the method compared to 'AnotherClass.as_dict()' below
return super(SomeClass, self).as_dict()
This is simply assigning BaseClass to SomeOtherClass, which means they can use BaseClass through both keywords.
SomeOtherClass = BaseClass
Related
Let's say I have a class with two methods, one will be decorated by a classmethod and the other one will not.
class MyClass():
def __init__(self):
self.my_string = 'Hello'
def test1(self):
return self.my_string
#classmethod
def test2(cls):
return cls().my_string
What is the difference between these two calls:
MyClass().test1()
MyClass.test2()
I checked the elapsed time of them and they differ a lot, so it got to be different somehow, but I can't understand why. Is there a preferable way of doing it? Thank you in advance.
They are very different.
MyClass().test1() invokes the instance method test1 with the instance MyClass() as its implicit first argument (bound to the parameter self).
MyClass.test2() invokes the class method test2 with the class MyClass as its implicit first argument (bound to the parameter cls).
You didn't ask about the more interesting MyClass().test2(), which still invokes the class method test2 with the class MyClass (the type of the instance) as its implicit first argument.
You also didn't ask about MyClass.test1(), which would raise a TypeError because MyClass.test1 resolves to an ordinary function, and no argument would be implicitly bound to the required parameter self.
This particular class method is strange. A class method should either be independent of any particular instance of the class, or create and return an instance. Creating an instance only for use in the class method doesn't really make sense.
There are two main ways for a derived class to call a base class's methods.
Base.method(self):
class Derived(Base):
def method(self):
Base.method(self)
...
or super().method():
class Derived(Base):
def method(self):
super().method()
...
Suppose I now do this:
obj = Derived()
obj.method()
As far as I know, both Base.method(self) and super().method() do the same thing. Both will call Base.method with a reference to obj. In particular, super() doesn't do the legwork to instantiate an object of type Base. Instead, it creates a new object of type super and grafts the instance attributes from obj onto it, then it dynamically looks up the right attribute from Base when you try to get it from the super object.
The super() method has the advantage of minimizing the work you need to do when you change the base for a derived class. On the other hand, Base.method uses less magic and may be simpler and clearer when a class inherits from multiple base classes.
Most of the discussions I've seen recommend calling super(), but is this an established standard among Python coders? Or are both of these methods widely used in practice? For example, answers to this stackoverflow question go both ways, but generally use the super() method. On the other hand, the Python textbook I am teaching from this semester only shows the Base.method approach.
Using super() implies the idea that whatever follows should be delegated to the base class, no matter what it is. It's about the semantics of the statement. Referring explicitly to Base on the other hand conveys the idea that Base was chosen explicitly for some reason (perhaps unknown to the reader), which might have its applications too.
Apart from that however there is a very practical reason for using super(), namely cooperative multiple inheritance. Suppose you've designed the following class hierarchy:
class Base:
def test(self):
print('Base.test')
class Foo(Base):
def test(self):
print('Foo.test')
Base.test(self)
class Bar(Base):
def test(self):
print('Bar.test')
Base.test(self)
Now you can use both Foo and Bar and everything works as expected. However these two classes won't work together in a multiple inheritance schema:
class Test(Foo, Bar):
pass
Test().test()
# Output:
# Foo.test
# Base.test
That last call to test skips over Bar's implementation since Foo didn't specify that it wants to delegate to the next class in method resolution order but instead explicitly specified Base. Using super() resolves this issue:
class Base:
def test(self):
print('Base.test')
class Foo(Base):
def test(self):
print('Foo.test')
super().test()
class Bar(Base):
def test(self):
print('Bar.test')
super().test()
class Test(Foo, Bar):
pass
Test().test()
# Output:
# Foo.test
# Bar.test
# Base.test
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.
I'm currently implementing some unit tests for my company's build scripts. To eliminate bloat and make it a little easier to implement new tests, I'm making all my test classes inherit from a custom subclass called BasicTest that inherits from PyUnit's TestCase.
There are currently two functions that all tests utilize from BasicTest: The constructor (Although it could obviously be overwritten in the future) and the runTest() method that is the default method name that the super's constructor uses if no value is passed in (e.g. BasicTest() would create a test that will execute the runTest() method when called upon, whereas BasicTest('Foo') would use the Foo() method).
I would like to make runTest() simply run all possible tests from the inheriting object it is called on. However, as runTest() is defined only in BasicTest and inherited by the subclasses, I'm looking for a way to dynamically call all of the subclass' methods from the super. I know this violates the rules of OO programming, but from what I can see, Python was never one to follow rules in the first place :)
For clarity, the following illustrates my intentions:
I want runTest() to be called from a subclass object and only handle that object's methods. Let's say SubclassTest() that has methods TestParse() and TestExec(). I want it so that:
sub = SubClassTest()
sub.runTest()
runs TestParse() and TestExec(), but I want the runTest() method to be defined in and inherited from BasicTest without being overriden.
one can create metaclass which will collect all interesting methods of subclasses into class property
class TestMetaclass(type):
def __new__(cls, name, bases, attrs):
own_tests = [v for k,v in attrs.iteritems() if k.startswith('test')]
attrs['test_method_list'] = own_tests
return super(TestMetaclass, cls).__new__(cls, name, bases, attrs)
set this metaclass to base class as __metaclass__
and implement runTests method
class BaseTest():
test_method_list = []
__metaclass__ = TestMetaclass
def runTests(self):
for method in self.test_method_list:
method(self)
And after this all subclasses will be constructed using this metaclass
class TestOne(BaseTest):
def test_foo(self):
pass
In the end one can use collected methods running runTests() method
TestOne().runTests()
Sample code:
load base class .py file as module
and inspect
import inspect
import imp
imp.load_source((name of class by which to want that module), (path base class name of file).py)
module = __import__((name of class by which to want that module))
inspect.getmembers(module) will give you dict of name, cls
Hope this helps
I have a module (db.py) which loads data from different database types (sqlite,mysql etc..) the module contains a class db_loader and subclasses (sqlite_loader,mysql_loader) which inherit from it.
The type of database being used is in a separate params file,
How does the user get the right object back?
i.e how do I do:
loader = db.loader()
Do I use a method called loader in the db.py module or is there a more elegant way whereby a class can pick its own subclass based on a parameter? Is there a standard way to do this kind of thing?
Sounds like you want the Factory Pattern. You define a factory method (either in your module, or perhaps in a common parent class for all the objects it can produce) that you pass the parameter to, and it will return an instance of the correct class. In python the problem is a bit simpler than perhaps some of the details on the wikipedia article as your types are dynamic.
class Animal(object):
#staticmethod
def get_animal_which_makes_noise(noise):
if noise == 'meow':
return Cat()
elif noise == 'woof':
return Dog()
class Cat(Animal):
...
class Dog(Animal):
...
is there a more elegant way whereby a class can pick its own subclass based on a parameter?
You can do this by overriding your base class's __new__ method. This will allow you to simply go loader = db_loader(db_type) and loader will magically be the correct subclass for the database type. This solution is mildly more complicated than the other answers, but IMHO it is surely the most elegant.
In its simplest form:
class Parent():
def __new__(cls, feature):
subclass_map = {subclass.feature: subclass for subclass in cls.__subclasses__()}
subclass = subclass_map[feature]
instance = super(Parent, subclass).__new__(subclass)
return instance
class Child1(Parent):
feature = 1
class Child2(Parent):
feature = 2
type(Parent(1)) # <class '__main__.Child1'>
type(Parent(2)) # <class '__main__.Child2'>
(Note that as long as __new__ returns an instance of cls, the instance's __init__ method will automatically be called for you.)
This simple version has issues though and would need to be expanded upon and tailored to fit your desired behaviour. Most notably, this is something you'd probably want to address:
Parent(3) # KeyError
Child1(1) # KeyError
So I'd recommend either adding cls to subclass_map or using it as the default, like so subclass_map.get(feature, cls). If your base class isn't meant to be instantiated -- maybe it even has abstract methods? -- then I'd recommend giving Parent the metaclass abc.ABCMeta.
If you have grandchild classes too, then I'd recommend putting the gathering of subclasses into a recursive class method that follows each lineage to the end, adding all descendants.
This solution is more beautiful than the factory method pattern IMHO. And unlike some of the other answers, it's self-maintaining because the list of subclasses is created dynamically, instead of being kept in a hardcoded mapping. And this will only instantiate subclasses, unlike one of the other answers, which would instantiate anything in the global namespace matching the given parameter.
I'd store the name of the subclass in the params file, and have a factory method that would instantiate the class given its name:
class loader(object):
#staticmethod
def get_loader(name):
return globals()[name]()
class sqlite_loader(loader): pass
class mysql_loader(loader): pass
print type(loader.get_loader('sqlite_loader'))
print type(loader.get_loader('mysql_loader'))
Store the classes in a dict, instantiate the correct one based on your param:
db_loaders = dict(sqlite=sqlite_loader, mysql=mysql_loader)
loader = db_loaders.get(db_type, default_loader)()
where db_type is the paramter you are switching on, and sqlite_loader and mysql_loader are the "loader" classes.