2012-01-17 56 views
5

我有一個永遠不會被實例化的基類。這個基類有不同的子類。每個子類都定義了某些類變量,其中名稱在所有子類中都是相同的,但值將會不同。例如python中每個子類中的類變量的不同值

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) 

什麼是設計這個,這樣我可以強制執行,如果明天的任何新的子類的定義,實現子類中的人應該提供一些值,這些類變量和不可錯過的定義的正確方法嗎?

回答

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

+1元類使用 – 2012-01-17 10:31:08

+0

我更喜歡@ SavinoSguera的解決方案,因爲它更簡單,代碼更少 - 這意味着更容易理解未來的代碼閱讀器 – Henning 2015-08-18 16:41:37

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

也許你可以在基類的初始化功能添加校驗碼,這樣的:

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

你可以在ciphor建議的構造函數中做一個簡單的檢查來做到這一點,但是你也可以在你的基類中使用裝飾器來確保你想要的屬性被定義。

然後解釋器將檢查,當一個實例的實例被創建日誌文件:

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()會更有意義。該方法從基地繼承,並且這樣避免了對基類進行硬編碼。如果你有更多的子類,那麼它也使得繼承鏈更清晰。

相關問題