2011-06-20 29 views
7

Tôi đang chạy Python 2.7 và tôi đang cố gắng tạo lớp con FloatEncoder tùy chỉnh của JSONEncoder. Tôi đã làm theo nhiều ví dụ như this nhưng không có ví dụ nào hoạt động. Đây là lớp FloatEncoder tôi:Tạo JSONEncoder tùy chỉnh

class FloatEncoder(JSONEncoder): 
    def _iterencode(self, obj, markers=None): 
     if isinstance(obj, float): 
      return (str(obj) for obj in [obj]) 
     return super(FloatEncoder, self)._iterencode(obj, markers) 

Và đây là nơi tôi gọi json.dumps:

with patch("utils.fileio.FloatEncoder") as float_patch: 
     for val,res in ((.0,'0.0012'),(.00009,'0.0001'),(0.99999,'1.0000'),({'hello':1.00001,'world':[True,1.00009]},'{"world": [true, 1.0001], "hello": 1.0000}')): 
      untrusted = dumps(val, cls=FloatEncoder) 
      self.assertTrue(float_patch._iterencode.called) 
      self.assertEqual(untrusted, res) 

Khẳng định đầu tiên thất bại, có nghĩa là _iterencode không được thực thi. Sau khi đọc tài liệu JSON, tôi đã cố gắng ghi đè phương thức default() nhưng cũng không được gọi.

+2

FWIW, 'mặc định()' không được gọi vì nếu đầu vào là một trong những loại bộ mã hóa hỗ trợ theo mặc định, nó sẽ thậm chí không nhìn vào phương pháp tùy chỉnh của bạn. So sánh 'lib/json/encoder.py', trong định nghĩa' _iterencode() ':' _default() 'chỉ được gọi trong nhánh' else: ', sau khi tất cả các kiểu đã biết đã được bảo hiểm. Do đó bạn không thể ghi đè lên xử lý cho một loại đã biết. – Tomalak

Trả lời

2

Bạn dường như đang cố gắng làm tròn các giá trị phao xuống 4 điểm thập phân trong khi tạo JSON (dựa trên các ví dụ kiểm tra).

JSONEncoder giao hàng bằng Python 2.7 không có phương thức _iterencode, vì vậy đó là lý do tại sao nó không được gọi. Xem nhanh json/encoder.py cho thấy rằng lớp này được viết theo cách làm cho việc thay đổi hành vi mã hóa float trở nên khó khăn. Có lẽ, sẽ tốt hơn nếu tách các mối quan tâm và làm tròn các phao trước khi thực hiện tuần tự hóa JSON.

EDIT: Alex Martelli còn cung cấp một giải pháp khỉ vá trong a related answer. Vấn đề với cách tiếp cận đó là bạn đang giới thiệu một sửa đổi toàn cầu để json hành vi thư viện mà có thể vô tình ảnh hưởng đến một số đoạn mã khác trong ứng dụng của bạn mà được viết với giả định rằng phao được mã hóa mà không làm tròn.

Hãy thử điều này:

from collections import Mapping, Sequence 
from unittest import TestCase, main 
from json import dumps 

def round_floats(o): 
    if isinstance(o, float): 
     return round(o, 4) 
    elif isinstance(o, basestring): 
     return o 
    elif isinstance(o, Sequence): 
     return [round_floats(item) for item in o] 
    elif isinstance(o, Mapping): 
     return dict((key, round_floats(value)) for key, value in o.iteritems()) 
    else: 
     return o 

class TestFoo(TestCase): 
    def test_it(self): 
     for val, res in ((.0, '0.0012'), 
         (.00009, '0.0001'), 
         (0.99999, '1.0'), 
         ({'hello': 1.00001, 'world': [True, 1.00009]}, 
          '{"world": [true, 1.0001], "hello": 1.0}')): 
      untrusted = dumps(round_floats(val)) 
      self.assertEqual(untrusted, res) 

if __name__ == '__main__': 
    main() 
-1

Không xác định _iterencode, xác định default, như được hiển thị trong câu trả lời thứ ba trên trang đó.

+1

Tôi đã thử điều đó nhưng cũng là vấn đề tương tự: phương thức default() không được gọi. – Matt