Python - empty class constructor (style) - python

What is a "Pythonic" way to define a class that does not need any constructor parameters?
class MyClass:
# class body
or do we need an explicit constructor? i.e.
class MyClass:
def __init__:
pass
# class body

Your first approach is good enough, unless you want to only use class attributes and not instance attributes
Also every class in Python inherits from object, as explained in detail here
class MyClass:
pass
An example of such classes might be as follows
A class to store multiple class attributes
class MyClass:
a = 1
b = 2
print(MyClass.a)
#1
print(MyClass.b)
#2
A custom exception where the constructor is implicitly taken from the base class
class MyException(Exception):
pass
raise MyException
# raise MyException
#__main__.MyException

Related

Using subclass static property in base class

I have one base class and other classes inherit from this class (subclasses). There is one common method in base class that I want to use subclass static properties If subclass has the properties; otherwise default base class property should be used.
I have written following code to do such a thing:
class Base:
prp1 = 1
prp2 = 2
def __init__():
pass
def method1(self):
# print subclass prp1 and prp2 if exist (how to do this?)
class Subclass(Base):
prp1 = 3
prp2 = 4
a = Subclass()
a.method1() # should print subclass properties (3, 4)
How to get around this problem?
Thanks in advance.
Your code works just fine - you can reference prp1 and prp2 using self, so:
def method1(self):
print(self.prp1)
print(self.prp2)
Will reference the properties from the instance of the class you're calling it on.
Furthermore, if you don't define prp2 on the subclass, Python will fallback to prp2 from Base, which I assume is what you want.
Calling the class from instance should do the thing:
print(self.__class__.prp1)

How to create abstract classes using abc without using an abstract method?

Using abc, I can create abstract classes using the following:
from abc import ABC, abstractmethod
class A(ABC):
#abstractmethod
def foo(self):
print('foo')
class B(A):
pass
obj = B()
This will fail because B has not defined the method foo.
This mimics the abstract method functionality in Java.
I wanted to know if the abstract class functionality is also present in Python, where instantiation of a class is prevented without having any abstract methods.
The conventional way to create an abstract class in Python is to raise the built-in exception NotImplementedError.
class A(object):
def __init__(self):
raise NotImplementedError('abstract base class')
class B(A):
def __init__(self):
# don't call A.__init__ here.
pass
b = B()
# a = A() # This will fail.
Yes. You can.
If you want to not enforce method implementation:
Simply inherit from ABC but don't delcare a method abstract, so it needn't be implemented in its subclasses.
If you want the abstract class to enforce the implementation of all methods:
Decorate all methods.
If you want to enforce the implementation of a method that does not belong to an ABC:
Raise NotImplementedErrorin the method. This won't prevent instantiation, but usage. However, if you want to prevent it in the instantiation, you should rather use ABC's.
You can also delcare __init__ an abstractmethod, but generally this does not look very useful to me.

Why does #abstractmethod need to be used in a class whose metaclass is derived from ABCMeta?

PEP 3119 states that:
The #abstractmethod decorator should only be used inside a class body, and only for classes whose metaclass is (derived from) ABCMeta. Dynamically adding abstract methods to a class, or attempting to modify the abstraction status of a method or class once it is created, are not supported.
I cannot find, however, an explanation of why that is. Specifically, I do not notice a difference in behavior when using only #abstractmethod in a class that does not explicitly inherit from ABCMeta. In the following simple example, if I understand correctly, the proper way of doing things would be:
import six
from abc import ABCMeta
from abc import abstractmethod
class Base(six.with_metaclass(ABCMeta)):
def __init__(self):
print('Init abstract base')
#abstractmethod
def do_something(self):
pass
class Subclass(Base):
def __init__(self):
super(Subclass, self).__init__()
def do_something(self):
print('Done.')
sub = Subclass()
sub.do_something()
However, if I let the Base class inherit simply from object, and only use the decorator when needed, I notice no change in behavior.
from abc import abstractmethod
class Base(object):
def __init__(self):
print('Init abstract base')
#abstractmethod
def do_something(self):
pass
class Subclass(Base):
def __init__(self):
super(Subclass, self).__init__()
def do_something(self):
print('Done.')
sub = Subclass()
sub.do_something()
I have found this to be the case even on more complex architectures, so I wonder: when does the latter method fail?
You don't see any difference because your first subclass does implement the do_something abstractmethod.
Comment out the definition of do_something in the subclasses in both versions and you'll find out that in the first case you get a TypeError when trying to instanciate the subclass - you'd also get one trying to instanciate the first version Base class itself FWIW. With the second version, you can instanciate both classes (which shouldn't be possible since they are abstract) and call the abstract do_something method - which kind of defeats one of main points of ABCs.
You'll also miss quite a few other interesting features of ABCs FWIW...

Extending a class hierarchy in Python

I have a class hierarchy in a module that I want to extend.
The module to be extended looks something like this.
Module foo:
class bar(object): pass
class spam(bar): pass
class eggs(bar): pass
Now I want to extend these classes:
class my_bar(foo.bar):
def new_func(): pass
class my_spam(foo.spam): pass
class my_eggs(foo.eggs): pass
Doing so, a new function new_func() in my_bar would not be available in a my_spam instance using
my_spam_instance.new_func()
What is the best ("most pythonic") way to achieve this? I thought of multiple inheritance, like this:
class my_bar(foo.bar): pass
class my_spam(foo.bar, my_bar): pass
class my_eggs(foo.eggs, my_bar): pass
Though I never really used it before and I am not sure this is the best way.
You don't even need to inherit my_bar from bar
pythonic will be adding Mixin, which is actually a base class, but not inherited
class NewFuncMixin():
def new_func(): pass
And add it to new classes
class my_bar(foo.bar, NewFuncMixin): pass
class my_spam(foo.spam, NewFuncMixin): pass
class my_eggs(foo.eggs, NewFuncMixin): pass
What about a mixin class? The pattern is
class My_mixin( object):
def new_func(self): pass
class My_spam( My_mixin, foo.spam): pass
class My_eggs( My_mixin, foo.eggs): pass
mixins should inherit from object, and go on the left of the inheritance list so that the mixin class methods get name priority. Within the mixin you can then wrap any method of the superclass:
class My_mixin( object):
def bar_method( self):
# stuff
bar_result = super( My_mixin, self).bar_method()
# more stuff
return bar_result # or my_result based on bar_result
You can of course completely override the method instead of wrapping it.

Can one declare an abstract exception in Python?

I would like to declare a hierarchy of user-defined exceptions in Python. However, I would like my top-level user-defined class (TransactionException) to be abstract. That is, I intend TransactionException to specify methods that its subclasses are required to define. However, TransactionException should never be instantiated or raised.
I have the following code:
from abc import ABCMeta, abstractmethod
class TransactionException(Exception):
__metaclass__ = ABCMeta
#abstractmethod
def displayErrorMessage(self):
pass
However, the above code allows me to instantiate TransactionException...
a = TransactionException()
In this case a is meaningless, and should instead draw an exception. The following code removes the fact that TransactionException is a subclass of Exception...
from abc import ABCMeta, abstractmethod
class TransactionException():
__metaclass__ = ABCMeta
#abstractmethod
def displayErrorMessage(self):
pass
This code properly prohibits instantiation but now I cannot raise a subclass of TransactionException because it's not an Exception any longer.
Can one define an abstract exception in Python? If so, how? If not, why not?
NOTE: I'm using Python 2.7, but will happily accept an answer for Python 2.x or Python 3.x.
There's a great answer on this topic by Alex Martelli here. In essence, it comes down how the object initializers (__init__) of the various base classes (object, list, and, I presume, Exception) behave when abstract methods are present.
When an abstract class inherits from object (which is the default, if no other base class is given), its __init__ method is set to that of object's, which performs the heavy-lifting in checking if all abstract methods have been implemented.
If the abstract class inherits from a different base class, it will get that class' __init__ method. Other classes, such as list and Exception, it seems, do not check for abstract method implementation, which is why instantiating them is allowed.
The other answer provides a suggested workaround for this. Of course, another option that you have is simply to accept that the abstract class will be instantiable, and try to discourage it.
class TransactionException(Exception):
def __init__(self, *args, **kwargs):
raise NotImplementedError('you should not be raising this')
class EverythingLostException(TransactionException):
def __init__(self, msg):
super(TransactionException, self).__init__(msg)
try:
raise EverythingLostException('we are doomed!')
except TransactionException:
print 'check'
try:
raise TransactionException('we are doomed!')
except TransactionException:
print 'oops'
My implementation for an abstract exception class, in which the children of the class work out of the box.
class TransactionException(Exception):
def __init__(self):
self._check_abstract_initialization(self)
#staticmethod
def _check_abstract_initialization(self):
if type(self) == TransactionException:
raise NotImplementedError("TransactionException should not be instantiated directly")
class AnotherException(TransactionException):
pass
TransactionException() # NotImplementedError: TransactionException should not be instantiated directly
AnotherException # passes
Here's a helper function that can be used in such scenario:
def validate_abstract_methods(obj):
abstract_methods = []
for name in dir(obj):
value = getattr(obj, name, None)
if value is not None and getattr(value, '__isabstractmethod__', False):
abstract_methods.append(name)
if abstract_methods:
abstract_methods.sort()
raise TypeError(f"Can't instantiate abstract class {obj.__class__.__name__} with abstract methods {', '.join(abstract_methods)}")
This function roughly does the same thing as abc.ABC class - you just need to call it from your class' __init__ method.

Categories

Resources