2011-04-07 32 views
6

Tôi đang cố gắng xây dựng một lớp kế thừa các phương thức từ danh sách của Python, nhưng cũng có thêm một số thứ trên đầu ... vào thời điểm này ...Giả lập phương thức list.insert() như là một lớp con của danh sách Python

class Host(object): 
    """Emulate a virtual host attached to a physical interface""" 
    def __init__(self): 
    # Insert class properties here... 
    pass 

class HostList(list): 
    """A container for managing lists of hosts""" 
    def __init__(self): 
     self = [] 

    def append(self, hostobj): 
     """append to the list...""" 
     if hostobj.__class__.__name__ == 'Host': 
      self.insert(len(self), hostobj) 
     else: 
      _classname = hostobj.__class__.__name__ 
      raise RuntimeError, "Cannot append a '%s' object to a HostList" % _classname 

vấn đề của tôi là thế này ... nếu tôi muốn thực hiện cùng một loại kiểm tra nhập học đối tượng trên insert() như tôi đã làm trên append(), tôi không thể tìm thấy một cách để mã hoá phương pháp mới mà không phải hy sinh hỗ trợ cho một phương pháp mở rộng danh sách (ví dụ: list.append(), list.insert() hoặc list.extend()). Nếu tôi cố gắng để hỗ trợ tất cả, tôi gió lên với các vòng đệ quy. Cách tốt nhất xung quanh vấn đề này là gì?

EDIT: Tôi đã gợi ý về subclassing collections.MutableSequence thay vì danh sách của Python()

Mã kết quả ... đăng ở đây trong trường hợp, nó giúp ai đó ...

from collections import MutableSequence 
class HostList(MutableSequence): 
    """A container for manipulating lists of hosts""" 
    def __init__(self, data): 
     super(HostList, self).__init__() 
     if (data is not None): 
      self._list = list(data) 
     else: 
      self._list = list() 

    def __repr__(self): 
     return "<{0} {1}>".format(self.__class__.__name__, self._list) 

    def __len__(self): 
     """List length""" 
     return len(self._list) 

    def __getitem__(self, ii): 
     """Get a list item""" 
     return self._list[ii] 

    def __delitem__(self, ii): 
     """Delete an item""" 
     del self._list[ii] 

    def __setitem__(self, ii, val): 
     # optional: self._acl_check(val) 
     return self._list[ii] 
    def __str__(self): 
     return str(self._list) 
    def insert(self, ii, val): 
     # optional: self._acl_check(val) 
     self._list.insert(ii, val) 
    def append(self, val): 
     self.insert(len(self._list), val) 
+4

'self = []' không làm những gì bạn nghĩ. –

+1

'super (HostList, self) .__ init __ (self)' sẽ làm thủ thuật. Những gì mã của bạn làm là gán lại biến (đối số) 'self' cho' [] '. –

+0

'__getitem__' sẽ trả về một đối tượng danh sách nếu một lát được chỉ định. Bạn có thể thay đổi initializer thành '__init __ (self, l = None)' sẽ sử dụng một danh sách nếu được cung cấp. Sau đó, trong '__getitem__', nếu ii là một đối tượng slice, sau đó trả về' HostList (self._list [ii]) ' –

Trả lời

7

Nếu bạn có thể tránh được điều đó, đừng kế thừa từ các lớp nội trang. (Bạn có thể , nhưng điều đó không có nghĩa là bạn nên mà không có một lý do thực sự hấp dẫn)

Những lớp học được tối ưu hóa cho tốc độ, và làm cho kế thừa từ họ một cách chính xác khá tẻ nhạt, vì bạn sẽ chỉ phải ghi đè gần như tất cả mọi thứ.

Kế thừa từ collections.MutableSequence thay vào đó cho phép bạn triển khai chỉ một vài phương pháp thiết yếu và có được triển khai mạnh mẽ đầy đủ tính năng API trình tự, mà không có tất cả các điều kỳ quặc và đi kèm với kế thừa từ list.

+0

Điểm tuyệt vời +1 ... Sau một số cuộc đấu tranh, tôi đã làm việc với 'collections.MutableSequence' ... Cảm ơn bạn! –

6

Sử dụng isinstance để kiểm tra các đối tượng của bạn để xem chúng là các trường hợp Host và sử dụng super (ví dụ: super(HostList, self).insert(...)) để sử dụng chức năng của list, thay vì tự thực hiện lại.

Bạn nên kết thúc với một cái gì đó như:

def append(self, obj): 
    """append to the list...""" 
    if not isinstance(obj, Host): 
     raise RuntimeError, "Cannot append a '%s' object to a HostList" % obj.__class__.__name__ 
    super(HostList, self).append(obj) 
+1

Thậm chí tốt hơn, xác định một phương thức tĩnh 'as_host (x)' trả về 'x' nếu nó là một máy chủ lưu trữ, khác ném ra ngoại lệ thích hợp. Sau đó, các cuộc gọi 'super' trở thành một lớp lót. –

0

Bạn có thể gọi list 's phương pháp từ phương pháp của bạn, với super(). Bằng cách đó bạn không cần phải kludge nó với các phương pháp khác.

3

Trừ khi nếu có lý do thuyết phục để bộ chứa HostList của bạn hoàn toàn hỗ trợ giao diện vùng chứa có thể thay đổi, tôi khuyên bạn nên sử dụng mô hình có chứ không phải là-a. Bạn sẽ có thêm gánh nặng đảm bảo tính nhất quán kiểu với các thao tác như slicing (trả về một container HostList thay vì một danh sách).

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