2010-03-06 21 views
56

Tôi đang gỡ lỗi một số mã và tôi muốn tìm hiểu khi nào một từ điển cụ thể được truy cập. Vâng, nó thực sự là một lớp học mà phân lớp dict và thực hiện một vài tính năng bổ sung. Dù sao, những gì tôi muốn làm là phân lớp dict bản thân mình và thêm ghi đè __getitem____setitem__ để tạo ra một số đầu ra gỡ lỗi. Ngay bây giờ, tôi cóLàm thế nào để đúng phân lớp dict và ghi đè __getitem__ & __setitem__

class DictWatch(dict): 
    def __init__(self, *args): 
     dict.__init__(self, args) 

    def __getitem__(self, key): 
     val = dict.__getitem__(self, key) 
     log.info("GET %s['%s'] = %s" % str(dict.get(self, 'name_label')), str(key), str(val))) 
     return val 

    def __setitem__(self, key, val): 
     log.info("SET %s['%s'] = %s" % str(dict.get(self, 'name_label')), str(key), str(val))) 
     dict.__setitem__(self, key, val) 

'name_label' là chìa khóa cuối cùng sẽ được đặt mà tôi muốn sử dụng để xác định đầu ra. Sau đó tôi đã thay đổi lớp tôi đang chuyển sang phân lớp DictWatch thay vì dict và thay đổi cuộc gọi đến superconstructor. Tuy nhiên, dường như không có gì xảy ra. Tôi nghĩ rằng tôi đã được thông minh, nhưng tôi tự hỏi nếu tôi nên đi một hướng khác nhau.

Cảm ơn sự giúp đỡ!

+0

Bạn đã cố gắng sử dụng in thay vì đăng nhập? Ngoài ra, bạn có thể giải thích làm thế nào để bạn tạo/cấu hình bạn đăng nhập? – pajton

+0

Không phải 'dict .__ init__' lấy' * args'? –

+1

Trông giống như một ứng cử viên tốt cho một người trang trí. –

Trả lời

24

Điều bạn đang làm hoàn toàn hoạt động. Tôi đã thử nghiệm lớp học của bạn, và ngoài một dấu mở ngoặc còn thiếu trong các câu lệnh tường trình của bạn, nó hoạt động tốt. Chỉ có hai điều tôi có thể nghĩ đến. Đầu tiên, đầu ra của câu lệnh đăng nhập của bạn có được đặt chính xác không? Bạn có thể cần phải đặt một số logging.basicConfig(level=logging.DEBUG) ở đầu tập lệnh của mình.

Thứ hai, __getitem____setitem__ chỉ được gọi trong khi truy cập []. Vì vậy, hãy chắc chắn rằng bạn chỉ truy cập DictWatch qua d[key], chứ không phải là d.get()d.set()

+0

Trên thực tế nó không phải là thêm parens, nhưng một thiếu mở paren xung quanh '(str (dict.get (tự, 'name_label')), str (key), str (val)))' – cobbal

+3

True. Đối với OP: Để tham khảo trong tương lai, bạn có thể chỉ cần đăng nhập.thông tin ('% s% s% s', a, b, c), thay vì một toán tử định dạng chuỗi Python. – BrainCore

+0

Tôi chỉ tìm thấy chuỗi định dạng tự nhiên hơn vì tôi thực hiện nhiều trường hợp. Đối với dấu ngoặc đơn, tôi gõ nhầm ở đây, bởi vì Python không phàn nàn về bất kỳ lỗi nào. –

7

Điều đó sẽ không thực sự thay đổi kết quả (mà nên làm việc, cho các giá trị ngưỡng khai thác gỗ tốt): bạn init nên là:

def __init__(self,*args,**kwargs) : dict.__init__(self,*args,**kwargs) 
Thay vào đó,

, vì nếu bạn gọi phương thức của mình bằng DictWatch ([(1,2), (2,3)]) hoặc DictWatch (a = 1, b = 2) thì điều này sẽ không thành công.

(hoặc, tốt hơn, không định nghĩa một constructor cho việc này)

+0

Tôi chỉ lo lắng về dạng truy cập 'dict [key]', vì vậy đây không phải là vấn đề. –

54

Một vấn đề khác khi subclassing dict là built-in __init__ không gọi update, và được xây dựng trong update không gọi __setitem__. Vì vậy, nếu bạn muốn tất cả các hoạt động SetItem phải đi qua chức năng __setitem__ của bạn, bạn nên chắc chắn rằng nó được gọi là bản thân:

class DictWatch(dict): 
    def __init__(self, *args, **kwargs): 
     self.update(*args, **kwargs) 

    def __getitem__(self, key): 
     val = dict.__getitem__(self, key) 
     print 'GET', key 
     return val 

    def __setitem__(self, key, val): 
     print 'SET', key, val 
     dict.__setitem__(self, key, val) 

    def __repr__(self): 
     dictrepr = dict.__repr__(self) 
     return '%s(%s)' % (type(self).__name__, dictrepr) 

    def update(self, *args, **kwargs): 
     print 'update', args, kwargs 
     for k, v in dict(*args, **kwargs).iteritems(): 
      self[k] = v 
+0

Nếu bạn đang sử dụng Python 3, bạn sẽ muốn thay đổi ví dụ này để 'print' là hàm' print() 'và phương thức' update() 'sử dụng' items() 'thay vì' iteritems() ' . –

0

Tất cả các bạn sẽ phải làm là

class BatchCollection(dict): 
    def __init__(self, inpt={}): 
     super(BatchCollection, self).__init__(inpt) 

Cách sử dụng mẫu cho sử dụng cá nhân của tôi

### EXAMPLE 
class BatchCollection(dict): 
    def __init__(self, inpt={}): 
     super(BatchCollection, self).__init__(inpt) 

    def __setitem__(self, key, item): 
     if (isinstance(key, tuple) and len(key) == 2 
       and isinstance(item, collections.Iterable)): 
      # self.__dict__[key] = item 
      super(BatchCollection, self).__setitem__(key, item) 
     else: 
      raise Exception(
       "Valid key should be a tuple (database_name, table_name) " 
       "and value should be iterable") 

Note: chỉ được thử nghiệm trong python3

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