Python 2.5的抽象类

时间:2011-07-01 12:55:09

标签: python refactoring

我目前正在重构一个定义客户端或服务器的类。这节课有很多

if client:
    XXXXXXXXXXXX
elif server:
    YYYYYYYYYYYY

所以我决定用类似的代码创建一个A类,为客户端创建一个C类,为继承A的服务器创建另一个S.(他们当然没有这些名称^^)

所以A类是某种抽象类。但问题是Python 2.5中没有抽象类,它带有2.6版本。所以我想知道是否有办法禁止A类实例化。

一种解决方案是在A类的构造函数中引发NotImplemented错误,但C和S的代码相同,所以我将它放在“抽象”类A中(不好主意?)。

这可能看起来很愚蠢,但我不时只在Python中开发,而且我是一名年轻的程序员。 你有什么建议?

6 个答案:

答案 0 :(得分:2)

这种方法的优点是你不需要对子类做任何事情就可以使它成为非抽象的。

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()

输出:

<__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!

如果要创建抽象子类,只需执行以下操作:

class AbstractSubclass(ABC):
    abstract = True

答案 1 :(得分:2)

在静态类型语言中,您使用抽象基类(ABC),因为您需要一些具有已定义大小,接口等的对象来传递。否则,无法编译试图调用该对象上的方法的代码。

Python不是静态类型的语言,调用代码根本不需要知道它所调用的对象的类型。因此,您可以通过记录接口要求并直接在两个不相关的类中实现该接口来“定义”您的ABC。

例如,

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)

在这里,您可以使用参数与调用匹配的do_thing方法传入任何对象。

答案 2 :(得分:1)

您可以在构造函数的开头调用方法“foo”。在A中,此方法引发异常。在C和S中,您重新定义“foo”,因此不再有例外。

答案 3 :(得分:1)

我的第一个问题是:为什么你不能简单地避免从类A实例化一个对象?我的意思是,这有点像questions on implementing singletons ...正如this answerer正确引用:

  

在“四人帮”得到所有学术之前,“单身人士”(没有正式名称)只是一个简单的想法,值得一个简单的代码行,而不是一个完整的宗教。

同样的 - IMO - 适用于抽象类(实际上已经在Python中引入了other reasons而不是你想要用它们的类。

也就是说,您可以在类__init__的{​​{1}}方法中引发异常。类似的东西:

A

当然这只是一个粗略的想法:如果你有{ - 1}}中的一些有用的东西,你应该检查>>> 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() >>> 属性等等......

答案 4 :(得分:0)

你想要的是abstract base class module

不适用于2.5。

答案 5 :(得分:0)

真正的问题是:你为什么需要一个抽象类?

如果你创建了2个类,并从第一个开始创建第二个类,那么这是一种清理代码的有效方法。