Different values ​​for class variables in each subclass in python

I have a base class that will never be created. There are different subclasses of this base class. Each subclass defines specific class variables, where the name is the same for all subclasses, but the value will be different. for instance

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)

What is the correct way to create it so that I can ensure that if any new subclass were defined, if the person implementing the subclass needs to provide some values ​​to these class variables and not miss their definition?

+5
source share
4 answers

One alternative that does not require instantiating classes for validation is to create a metaclass:

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
+10
source

>>> 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
+7

, 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/ .

One more note - when you have subclasses calling Base.display (self) in your original example, it would be wiser if they called self.display (). The method inherits from the base, and thus avoids the hard coding of the base class. If you have more subclasses, this also clears the inheritance chain.

+6
source

Perhaps you can add control code to the init function of the base class, for example:

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)
+2
source

All Articles