开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜