Abstract class with Python 2.5
I currently refactor a class defining a client or a server. The class had a lot of
if client:
XXXXXXXXXXXX
elif server:
YYYYYYYYYYYY
So I decided to create a class A with the similar cod开发者_JAVA百科e and one class C for the client and an other one S for the server which inherit A. (they don't have theses names of course ^^)
So class A is some kind of abstract class. But the problem is there is no abstract classes in Python 2.5, it comes with 2.6 version. So I was wondering if there is a way to forbid instantiations of class A.
One solution would have been to raise a NotImplemented error in the constructor of the class A, but C and S have the same code for it so I put it in the "abstract" class A (bad idea ?).
This may seem stupid but I develop in Python only from time to time and I'm a young programmer. What are your advices?
In statically-typed languages, you use an abstract base class (ABC) because you need some object with a defined size, interface etc. to pass around. Otherwise, the code trying to call methods on that object can't be compiled.
Python isn't a statically-typed language, and the calling code doesn't need to know the type of the object it's calling at all. So, you can "define" your ABC just by documenting the interface requirements, and implementing that interface directly in two unrelated classes.
Eg,
class Server:
def do_thing(self):
pass #do that server thing here
class Client:
def do_thing(self):
pass #do that client thing here
def do_thing(thingy):
thingy.do_thing() # is it a Client? a Server? something else?
s=Server()
c=Client()
do_thing(s)
do_thing(c)
Here, you could pass in any object with a do_thing method whose arguments match the call.
This approach has the advantage that you do not need to do anything to the subclass to make it non-abstract.
class ABC(object):
abstract = True
def __new__(cls, *args, **kwargs):
if "abstract" in cls.__dict__ and cls.__dict__["abstract"] == True:
raise RuntimeError(cls.__name__ + " is abstract!")
return object.__new__(cls)
class Subclass(ABC):
pass
print Subclass()
print ABC()
Output:
<__main__.Subclass object at 0xb7878a6c>
Traceback (most recent call last):
File "abc.py", line 14, in <module>
print ABC()
File "abc.py", line 6, in __new__
raise RuntimeError(cls.__name__ + " is abstract!")
RuntimeError: ABC is abstract!
If you want to create an abstract subclass, simply do like this:
class AbstractSubclass(ABC):
abstract = True
You can call a method "foo" at the beginning of A constructor. In A, this method raises an exception. In C and in S, you redefine "foo" so there is no more exceptions.
My first question is: why can't you simply avoid to instantiate an object from class A
? What I mean is that this is a bit like questions on implementing singletons... As this answerer correctly quoted:
Before the Gang of Four got all academic on us, "singleton" (without the formal name) was just a simple idea that deserved a simple line of code, not a whole religion.
The same - IMO - applies to abstract classes (which in fact have been introduced in Python for other reasons than the one you would intend to use them for.
That said, you could raise an exception in the __init__
method of class A
. Something like:
>>> class A():
... def __init__(self):
... raise BaseException()
...
>>> a = A()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
BaseException
>>> class B(A):
... def __init__(self):
... pass
...
>>> b = B()
>>>
Of course this is just an rough idea: if you have - for example - some useful stuff in the A.__init__
you should check the __class__
attribute, etc...
The real question is: why do you need an abstract class?
if you make 2 classes, and make the second herit from the first, it is an efficient way to clean your code.
There's an abstract base class module for what you want.
Not applicable for 2.5.
精彩评论