2012-01-17 33 views
5

Tôi có một lớp cơ sở không bao giờ được khởi tạo. Có các lớp con khác nhau của lớp cơ sở này. Mỗi phân lớp định nghĩa các biến lớp nhất định trong đó tên giống nhau trên tất cả các lớp con nhưng giá trị sẽ khác nhau. Ví dụcác giá trị khác nhau cho các biến lớp trong mỗi phân lớp trong 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) 

đúng cách để thiết kế này như vậy mà tôi có thể thực thi rằng nếu ngày mai bất kỳ lớp con mới được xác định, người thực hiện các lớp con nên cung cấp một số giá trị các biến lớp học và không bỏ lỡ định nghĩa chúng là gì?

Trả lời

10

Một thay thế mà không cần instantiating lớp để việc kiểm tra diễn ra là tạo một 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 
+1

+1 để sử dụng metaclass –

+0

Tôi thích giải pháp của @ SavinoSguera vì nó đơn giản hơn và ít mã hơn - có nghĩa là dễ hiểu hơn đối với người đọc mã trong tương lai – Henning

7

này nên làm việc

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

Có lẽ bạn có thể thêm kiểm tra mã trong init chức năng của lớp Base, như thế này:

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

Bạn có thể làm điều này với một kiểm tra đơn giản trong hàm khởi tạo như đã đề cập, nhưng bạn cũng có thể sử dụng trình trang trí abc.abstractproperty trong lớp cơ sở của mình để đảm bảo rằng thuộc tính giống như bạn muốn được xác định.

Sau đó, người phiên dịch sẽ kiểm tra xem các logfile được tạo ra khi một thể hiện được khởi tạo:

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 

Xem http://docs.python.org/library/abc.html và có lẽ hữu ích hơn: http://www.doughellmann.com/PyMOTW/abc/ để biết thêm chi tiết.

Một lưu ý nữa - khi bạn có các lớp con của bạn gọi Base.display (self) trong ví dụ ban đầu của bạn sẽ có ý nghĩa hơn khi gọi chúng là self.display(). Phương thức này được thừa hưởng từ cơ sở, và cách này tránh khó mã hóa lớp cơ sở. Nếu bạn có nhiều lớp con phụ thì nó cũng làm cho chuỗi kế thừa sạch hơn.

Các vấn đề liên quan