2013-05-10 10 views
7

Tôi có một số lớp học Python rằng, nếu đơn giản, giống như sau:Python - đánh máy OK khi lỗi sẽ không được ném khác?

class base: 
    def __init__(self, v): 
     self.value = v 

    def doThings(self): 
     print "Doing things." 

    def doMoreThings(self): 
     print "Doing more things." 

    def combine(self, b): 
     self.value += b.value 

class foo(base): 
    def showValue(self): 
     print "foo value is %d." % self.value 

class bar(base): 
    def showValue(self): 
     print "bar value is %d." % self.value 

Lớp base chứa phương pháp (đại diện trên bởi doThingsdoMoreThings) mà thực hiện chức năng chung cho cả foobar lớp con. Các lớp con foobar khác nhau về cơ bản trong cách chúng diễn giải trường value. (Ở trên, chúng chỉ khác với những gì chúng hiển thị khi in, nhưng trong ứng dụng thực tế của chúng tôi, chúng làm nhiều thứ phức tạp hơn.) base có thể được coi là "trừu tượng": người dùng chỉ làm việc với foo s và bar S. base chỉ tồn tại như một ngôi nhà cho mã chung cho các lớp con của nó.

Phương pháp tôi muốn hỏi là combine, cho phép bạn lấy hai trong số các đối tượng này và tạo một đối tượng thứ ba. Bởi vì foobar giải thích value cách khác nhau, nó không có ý nghĩa để combine hai lớp con của các loại khác nhau: bạn có thể combine hai foo s để có được một foo hoặc hai bar s để có được một bar nhưng không phải là một foobar. Mặc dù vậy, thủ tục cho combinecùng một số cho tất cả các lớp con, do đó, điều này có ý nghĩa khi được xác định và xác định ở một nơi.

Tôi có thể muốn báo hiệu lỗi nếu người dùng cố gắng combine hai đối tượng không tương thích, nhưng tôi không thấy cách để làm điều này mà không đưa vào các lỗi đánh máy xấu xí. Có thực hành tốt để làm điều này? Hoặc tôi nên làm điều bình thường và không kiểm tra, ghi lại vấn đề và giả sử rằng người dùng sẽ không cố gắng sử dụng combine theo cách không được dự định, mặc dù việc sử dụng đó có vẻ như "thành công" và trả lại rác đối tượng thay vì tăng lỗi?

Cảm ơn sự giúp đỡ của bạn.

Trả lời

3

Tôi thấy một số cách tiếp cận ở đây:

  1. Không kiểm tra bất cứ điều gì và tin tưởng người sử dụng để làm điều đúng. Có thể là thích hợp hoặc nguy hiểm, tùy thuộc vào tình hình.

  2. Kiểm tra loại. Bạn đúng là nó trông xấu xí, nhưng là điều dễ nhất.

  3. Không có value, nhưng đặt tên theo cách mà chúng dự định có (pressure, temperature) và để chúng tự kết hợp.

  4. Tương tự như 3, nhưng thêm các lớp con có property để ánh xạ truy cập vào .value đến biến giá trị "thực" tương ứng của chúng. Bằng cách này, bạn có thể giữ. __init__(), nhưng .combine() sẽ phải được thực hiện bởi mọi lớp con.

  5. Tương tự như 4 nhưng không sử dụng property, nhưng tự chế descriptor. Trong this answer, tôi cho thấy làm thế nào nó có thể được thực hiện.

2

Alter phương pháp kết hợp

def combine(self, b): 
    if (not(self.__class__.__name__ == b.__class__.__name__)): 
     raise TypeError("%s cannot combine with %s" % (self.__class__.__name__, b.__class__.__name__)) 
    else:   
     self.value += b.value 

Ngoài ra, thay đổi định nghĩa lớp cho cơ sở để

class base(object): 

và sau đó một đơn giản hơn, đẹp hơn, hạnh phúc hơn kết hợp phương pháp là có thể (nhờ glglgl)

def combine(self, b): 
    if (not(type(self) == type(b))): 
     raise TypeError("%s cannot combine with %s" % 
         (type(self), type(b))) 
    else:   
     self.value += b.value 
+0

So sánh '__class __.__ name__' là IMHO rất xấu xí. Một cách tốt hơn là so sánh 'loại (tự) == loại (b)' hoặc sử dụng 'isinstance (b, type (self))'. – glglgl

+0

@glglgl '' type (self) == type (b) '' luôn đúng vì cả hai đều là '' instance''. '' isinstance'' có cùng một vấn đề. Đồng ý điều đó thật xấu xí nhưng ... – Vorsprung

+0

Ouch! Không thấy OP sử dụng các lớp học kiểu cũ ... sau đó nó rõ ràng. (Tôi cố gắng tránh chúng bất cứ khi nào có thể.) Nhưng với 'isinstance', nó cũng nên làm việc với các lớp kiểu cũ (chỉ cần kiểm tra). – glglgl

0

Khi tôi w orked trên mã sản xuất mà sẽ không thất bại, tôi sử dụng một trang trí đảm bảo rằng một chức năng nguy hiểm sẽ không phát nổ, biến thành một quả cầu lửa và thổi toàn bộ hệ thống của tôi.

def bulltproof(func): 
    def _bulletproof(*args, **kwargs): 
     try: 
      result = func(*args, **kwargs) 
     except Exception as exc: 
      raise BulletproofError(exc) 
     return result 
    return _bulletproof 

Sử dụng nó như thế:

@bulletproof 
def some_risky_function(): 
    #.... 

Và bắt chỉ có một lỗi:

try: 
    some_risky_function() 
except Bulletproof: 
... 

Thay vì nâng lỗi bạn có thể trở None, đăng nhập lỗi hoặc tắt nó đi để thử nghiệm . Tất nhiên, cách tiếp cận này rất hữu ích khi bạn muốn đảm bảo rằng chương trình của bạn sẽ khôi phục từ lỗi, nhưng đôi khi tốt hơn là nên tiếp tục với lỗi

0

Vì việc thực hiện hoàn toàn khác nhau tùy thuộc vào đối tượng là foo hay không bar, tôi nghĩ rằng nó có ý nghĩa KHÔNG có chức năng trong phụ huynh trừu tượng, nhưng để giữ nó trong các lớp học có nguồn gốc. Ngay cả khi đó là cùng một mã, kết hợp hai trường hợp của foo sẽ là một hoạt động khác với kết hợp hai trường hợp của bar. Nếu mã cho .combine() thực sự rất dài, bạn có thể tạo một phương thức riêng trong lớp cơ sở để thực hiện công việc, nhưng chỉ gọi nó từ các hàm được định nghĩa trong lớp dẫn xuất.