我有一个永远不会被实例化的基类。这个基类有不同的子类。每个子类定义某些类变量,其中所有子类的名称相同,但值将不同。例如
class Base:
def display(self):
print self.logfile, self.loglevel
class d1(Base):
logfile = "d1.log"
loglevel = "debug"
def temp(self):
Base.display(self)
class d2(Base):
logfile = "d2.log"
loglevel = "info"
def temp(self):
Base.display(self)
设计这个的正确方法是什么,以便我可以强制执行,如果明天任何新的子类被定义,实现子类的人应该为这些类变量提供一些值而不是错过定义它们?
答案 0 :(得分:10)
一个不需要实例化类以进行检查的替代方法是创建一个元类:
class BaseAttrEnforcer(type):
def __init__(cls, name, bases, d):
if 'loglevel' not in d:
raise ValueError("Class %s doesn't define loglevel attribute" % name)
type.__init__(cls, name, bases, d)
class Base(object):
__metaclass__ = BaseAttrEnforcer
loglevel = None
class d1(Base):
logfile = "d1.log"
loglevel = "debug"
class d2(Base):
logfile = "d2.log"
loglevel = "info"
class d3(Base):
logfile = "d3.log"
# I should fail
答案 1 :(得分:7)
这应该有效
>>> class Base(object):
... def __init__(self):
... if not hasattr(self, "logfile"):
... raise Exception("not implemented")
...
>>> class d1(Base):
... logfile='logfile1.log'
...
>>> class d2(Base):
... pass
...
>>> d1()
<__main__.d1 object at 0x7d0d0>
>>> d2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __init__
not implemented
答案 2 :(得分:6)
您可以通过ciphor建议的构造函数中的简单检查来执行此操作,但您也可以在基类中使用 abc.abstractproperty 装饰器来确保属性类似于您想要的属性被定义为。
然后解释器将检查实例化实例时是否创建了日志文件:
import abc
#It is almost always a good idea to have your base class inherit from object
class Base(object):
__metaclass__ = abc.ABCMeta
@abc.abstractproperty
def logfile(self):
raise RuntimeError("This should never happen")
class Nice(Base):
@property
def logfile(self):
return "actual_file.log"
class Naughty(Base):
pass
d=Nice() #This is fine
print d.logfile #Prints actual_file.log
d=Naughty() #This raises an error:
#TypeError: Can't instantiate abstract class Base with abstract methods logfile
请参阅 http://docs.python.org/library/abc.html 并且可能更有用: http://www.doughellmann.com/PyMOTW/abc/ 了解更多详情。
还有一个注意事项 - 当您的子类在原始示例中调用Base.display(self)时,让它们调用self.display()会更有意义。该方法继承自base,这样就避免了对基类进行硬编码。如果你有更多的子类,那么它也会使继承链变得更清晰。
答案 3 :(得分:2)
也许您可以在Base类的 init 函数中添加检查代码,如下所示:
class Base:
logfile = ""
loglevel = ""
def __init__(self):
if len(self.logfile) == 0 or len(self.loglevel) == 0:
print 'WARNING: logfile & loglevel must be set!'
def display(self):
print self.logfile, self.loglevel
class d1(Base):
logfile = "d1.log"
loglevel = "debug"
def temp(self):
Base.display(self)
class d2(Base):
logfile = "d2.log"
loglevel = "info"
def temp(self):
Base.display(self)