разные значения для переменных класса в каждом подклассе в Python - PullRequest
5 голосов
/ 17 января 2012

У меня есть базовый класс, который никогда не будет создан.Существуют разные подклассы этого базового класса.Каждый подкласс определяет определенные переменные класса, где имя одинаково во всех подклассах, но значение будет другим.Например,

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)

Как правильно спроектировать это так, чтобы я мог обеспечить, чтобы, если завтра будет определен какой-либо новый подкласс, человек, реализующий подкласс, должен предоставить некоторые значения этим переменным класса и не пропустить определениеих?

Ответы [ 4 ]

10 голосов
/ 17 января 2012

Одна альтернатива, которая не требует создания экземпляров классов для проверки, состоит в создании метакласса:

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
7 голосов
/ 17 января 2012

Вы можете сделать это с помощью простой проверки в конструкторе, как предложил 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 ().Метод наследуется от базового, и таким образом избегает жесткого кодирования базового класса.Если у вас есть больше подклассов, это также делает цепочку наследования более чистой.

7 голосов
/ 17 января 2012

Это должно работать

>>> 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 голосов
/ 17 января 2012

Может быть, вы можете добавить проверочный код в функцию 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...