Preventing a class from direct instantiation in Python
我有一个超类,其中的一个方法调用了仅在其子类中定义的其他方法。这就是为什么,当我创建一个超级类的实例并调用它的方法时,它找不到该方法并引发错误。
下面是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | class SuperClass(object): def method_one(self): value = self.subclass_method() print value class SubClassOne(SuperClass): def subclass_method(self): return 'subclass 1' class SubClassTwo(SuperClass): def subclass_method(self): return 'nubclass 2' s1 = SubClassOne() s1.method_one() s2 = SubClassTwo() s2.method_one() c = SuperClass() c.method_one() # Results: # subclass 1 # nubclass 2 # Traceback (most recent call last): # File"abst.py", line 28, in <module> # c.method_one() # File"abst.py", line 4, in method_one # value = self.subclass_method() # AttributeError: 'SuperClass' object has no attribute 'subclass_method' |
在创建新实例时,我正在考虑更改super类的init并验证对象的类型。如果对象属于超级类,则引发错误。不过,我不太确定这是不是用了Python的方式。
有什么建议吗?
我将重写基类中的
1 2 3 4 5 6 | class BaseClass(object): def __new__(cls, *args, **kwargs): if cls is BaseClass: raise TypeError("base class may not be instantiated") return object.__new__(cls, *args, **kwargs) |
这比把它放在
您的方法是典型的框架模式。
使用uuu init_uuu验证
另一种常见的方法是在调用时提供
您所说的是抽象基类,而Python语言本身不支持它们。
但是,在标准库中,有一个模块可以用来帮助您。查看ABC文档。
我可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 | class SuperClass(object): def __init__(self): if type(self) == SuperClass: raise Exception("<SuperClass> must be subclassed.") # assert(type(self) == SuperClass) class SubClass(SuperClass): def __init__(self): SuperClass.__init__(self) subC = SubClassOne() supC = SuperClass() # This line should throw an exception |
运行时(引发异常!):
1 2 3 4 5 6 7 | [ 18:32 jon@hozbox ~/so/python ]$ ./preventing-direct-instantiation.py Traceback (most recent call last): File"./preventing-direct-instantiation.py", line 15, in <module> supC = SuperClass() File"./preventing-direct-instantiation.py", line 7, in __init__ raise Exception("<SuperClass> must be subclassed.") Exception: <SuperClass> must be subclassed. |
编辑(来自注释):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | [ 20:13 jon@hozbox ~/SO/python ]$ cat preventing-direct-instantiation.py #!/usr/bin/python class SuperClass(object): def __init__(self): if type(self) == SuperClass: raise Exception("<SuperClass> must be subclassed.") class SubClassOne(SuperClass): def __init__(self): SuperClass.__init__(self) class SubSubClass(SubClassOne): def __init__(self): SubClassOne.__init__(self) class SubClassTwo(SubClassOne, SuperClass): def __init__(self): SubClassOne.__init__(self) SuperClass.__init__(self) subC = SubClassOne() try: supC = SuperClass() except Exception, e: print"FAILED: supC = SuperClass() - %s" % e else: print"SUCCESS: supC = SuperClass()" try: subSubC = SubSubClass() except Exception, e: print"FAILED: subSubC = SubSubClass() - %s" % e else: print"SUCCESS: subSubC = SubSubClass()" try: subC2 = SubClassTwo() except Exception, e: print"FAILED: subC2 = SubClassTwo() - %s" % e else: print"SUCCESS: subC2 = SubClassTwo()" |
印刷品:
1 2 3 4 | [ 20:12 jon@hozbox ~/SO/python ]$ ./preventing-direct-instantiation.py FAILED: supC = SuperClass() - <SuperClass> must be subclassed. SUCCESS: subSubC = SubSubClass() SUCCESS: subC2 = SubClassTwo() |