পাইথন জেএসওএন একটি দশমিক অবজেক্টকে সিরিয়ালাইজ করে


242

আমার Decimal('3.9')একটি অবজেক্টের অংশ হিসাবে রয়েছে এবং এটিকে JSON স্ট্রিংয়ে এনকোড করতে চাই যা দেখতে ভাল লাগবে {'x': 3.9}। আমি ক্লায়েন্টের পক্ষ থেকে নির্ভুলতার বিষয়ে চিন্তা করি না, তাই একটি ভাসা ভাল।

এটির সিরিয়ালাইজ করার জন্য কি কোনও ভাল উপায় আছে? JSONDecoder দশমিক অবজেক্ট গ্রহণ করে না, এবং ফল্টের পূর্বে ফলন {'x': 3.8999999999999999}যা রূপান্তরিত তা রূপান্তরিত করে , এবং এটি ব্যান্ডউইথের একটি বড় অপচয় waste


2
সম্পর্কিত পাইথন বাগ:
জেসন

3.8999999999999999 3.4 এর চেয়ে বেশি ভুল নয়। 0.2 এর সঠিক ভাসমান উপস্থাপনা নেই।
জেসেন

@ জেসেন ৩.৮৯৯৯৯৯৯৯৯৯৯.৯.৪ এর তুলনায় প্রায় ১২.৮% বেশি ভুল। জেএসএন স্ট্যান্ডার্ডটি কেবল সিরিয়ালাইজেশন এবং স্বীকৃতি সম্পর্কিত, বাস্তবায়ন নয়। আইইইই 7575৫ ব্যবহার করা কাঁচা জেএসওএন স্পেকের অংশ নয়, এটি প্রয়োগের এটি কেবল সর্বাধিক সাধারণ উপায়। একটি বাস্তবায়ন যা কেবলমাত্র সুনির্দিষ্ট দশমিক গাণিতিক ব্যবহার করে তা সম্পূর্ণ (বাস্তবে আরও কঠোরভাবে) অনুসারী।
hraban

😂 কম ভুল বিদ্রূপাত্মক।
hraban

উত্তর:


147

সাবক্লাসিংয়ের কীভাবে json.JSONEncoder?

class DecimalEncoder(json.JSONEncoder):
    def _iterencode(self, o, markers=None):
        if isinstance(o, decimal.Decimal):
            # wanted a simple yield str(o) in the next line,
            # but that would mean a yield on the line with super(...),
            # which wouldn't work (see my comment below), so...
            return (str(o) for o in [o])
        return super(DecimalEncoder, self)._iterencode(o, markers)

তারপরে এটির মতো ব্যবহার করুন:

json.dumps({'x': decimal.Decimal('5.5')}, cls=DecimalEncoder)

ওহ, আমি কেবল লক্ষ্য করেছি যে এটি আসলে এর মতো কাজ করবে না। সেই অনুসারে সম্পাদনা করবে। (ধারণাটি একই থাকে, যদিও।)
মাইচা মার্কজিক

সমস্যাটি হ'ল DecimalEncoder()._iterencode(decimal.Decimal('3.9')).next()সঠিকটি ফিরিয়েছিল '3.9', তবে এমন DecimalEncoder()._iterencode(3.9).next()একটি জেনারেটরের বস্তুটি ফিরিয়ে দিয়েছে যা কেবলমাত্র '3.899...'যখন আপনি অন্যটিতে গাদা রাখেন তখনই ফিরে আসবে .next()। জেনারেটর মজার ব্যবসা। ওহ ভাল ... এখন কাজ করা উচিত।
মিচা মার্সেকেক

8
আপনি ঠিক return (str(o),)পরিবর্তে না পারেন ? [o]কেবলমাত্র 1 টি উপাদান সহ একটি তালিকা, কেন এটি লুপিং বিরক্ত করবেন?
এমপেইন

2
@ মার্ক: উত্তরের return (str(o),)দৈর্ঘ্যের দ্বিগুণ ফিরে আসবে, যখন উত্তরে কোড দৈর্ঘ্যের জেনারেটর প্রদান করবে। পুনরায় কোড () ডকগুলি
অ্যাবগান

30
এই বাস্তবায়ন আর কাজ করে না। ইলিয়াস জামারিয়ার একজন একই স্টাইলে কাজ করছেন।
পাইরো

223

সিম্পলজসন ২.১ এবং উচ্চতর দশমিক প্রকারের জন্য স্থানীয় সমর্থন রয়েছে:

>>> json.dumps(Decimal('3.9'), use_decimal=True)
'3.9'

ডিফল্ট হিসাবে use_decimalএটি নোট True:

def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
    allow_nan=True, cls=None, indent=None, separators=None,
    encoding='utf-8', default=None, use_decimal=True,
    namedtuple_as_object=True, tuple_as_array=True,
    bigint_as_string=False, sort_keys=False, item_sort_key=None,
    for_json=False, ignore_nan=False, **kw):

তাই:

>>> json.dumps(Decimal('3.9'))
'3.9'

আশা করি, এই বৈশিষ্ট্যটি স্ট্যান্ডার্ড লাইব্রেরিতে অন্তর্ভুক্ত করা হবে।


7
হুম, আমার জন্য এটি দশমিক অবজেক্টগুলিকে ফ্লোটে রূপান্তরিত করে, যা গ্রহণযোগ্য নয়। উদাহরণস্বরূপ, মুদ্রার সাথে কাজ করার সময় নির্ভুলতার ক্ষতি।
ম্যাথু শিংকেল

12
@ ম্যাথেজচেঙ্কেল আমার মনে হয় এটি হয় না। এটি আসলে এটি থেকে একটি স্ট্রিং তৈরি করে। এবং যদি আপনি ফলস্বরূপ স্ট্রিংটিকে json.loads(s, use_decimal=True)এটির কাছে ফিরিয়ে দেন তবে আপনাকে দশমিকটি ফিরে দেয়। পুরো প্রক্রিয়াটিতে কোনও ভাসা নেই। উপরে উত্তর সম্পাদিত। আশা করি মূল পোস্টারটি এটির সাথে ভাল।
শেখর

1
আহা, আমি মনে করি আমিও বোঝাটি ব্যবহার করছিলাম না use_decimal=True
ম্যাথু শিনকেল

1
আমার জন্য json.dumps({'a' : Decimal('3.9')}, use_decimal=True)দেয় '{"a": 3.9}'। লক্ষ্য ছিল না '{"a": "3.9"}'?
মিঃ জে

5
simplejson.dumps(decimal.Decimal('2.2'))এছাড়াও কাজ করে: কোন সুস্পষ্ট নয় use_decimal(সিম্পজসন / 3.6.0 এ পরীক্ষিত)। এটি আবার লোড করার আরেকটি উপায় হ'ল: json.loads(s, parse_float=Decimal)আপনি এটি স্টডিলিব ব্যবহার করে পড়তে পারেন json(এবং পুরানো simplejsonসংস্করণগুলিও সমর্থিত)।
jfs

181

আমি সবাইকে বলতে চাই যে আমি আমার ওয়েব সার্ভারে মাইচা মার্কসিকের উত্তরটি চেষ্টা করেছি যা পাইথন ২.6.৫ চালাচ্ছিল এবং এটি দুর্দান্ত কাজ করেছে। তবে আমি পাইথন ২.on এ আপগ্রেড করেছি এবং এটি কাজ বন্ধ করে দিয়েছে। আমি দশমিক অবজেক্টগুলিকে এনকোড করার জন্য কিছু উপায়ের কথা ভাবার চেষ্টা করেছি এবং এটিই আমি নিয়ে এসেছি:

import decimal

class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            return float(o)
        return super(DecimalEncoder, self).default(o)

পাইথন ২.7 এর সমস্যা রয়েছে এমন ব্যক্তির পক্ষে এটি আশা করা উচিত। আমি এটি পরীক্ষা করেছি এবং মনে হচ্ছে এটি ঠিক আছে। যদি কেউ আমার সমাধানটিতে কোনও বাগ লক্ষ্য করে বা আরও ভাল উপায় নিয়ে আসে তবে দয়া করে আমাকে জানান।


4
পাইথন ২.7 রাউন্ড ফ্লোটের নিয়মগুলিকে পরিবর্তন করেছে যাতে এটি কাজ করে। স্ট্যাকওভারফ্লো
নেলসন

2
আমাদের মধ্যে যারা সিম্পজসন ব্যবহার করতে পারবেন না (যেমন গুগল অ্যাপ ইঞ্জিনে) এই উত্তরটি গডসেন্ড।
জোয়েল ক্রস

17
নির্ভুলতা নিশ্চিত করতে ব্যবহার করুন unicodeবা strপরিবর্তে float
সেপ্পো এরভিউলি

2
পাইথন ২.6.x এবং তার চেয়ে পুরনো ক্ষেত্রে 54.3999 ... এর সমস্যাটি গুরুত্বপূর্ণ ছিল যেখানে স্ট্রিং-এ রূপান্তরটি নিয়মিত কাজ করে না, তবে দশমিক দশকে রূপান্তরটি অনেক বেশি ভুল কারণ এটি ডাবল উদ্ধৃতি সহ স্ট্রিং হিসাবে সিরিয়ালযুক্ত হবে, এমনটি "54.4"নয় একটি সংখ্যা.
hynekcer


43

আমার ফ্লাস্ক অ্যাপ্লিকেশনটিতে, যা পাইথন ২.7.১১ ব্যবহার করে, ফ্লাস্ক অ্যালকেমি ('ডিবি.ডিসিমাল' প্রকার সহ), এবং ফ্লাস্ক মার্শমালো ('তাত্ক্ষণিক' সিরিয়ালাইজার এবং ডিজিজারাইজারের জন্য) ব্যবহার করেছে, প্রতিবারই আমি জিইটি বা পোস্ট দিয়েছিলাম । সিরিয়ালাইজার এবং ডিসরিয়ালাইজার, দশমিক প্রকারকে কোনও JSON শনাক্তযোগ্য ফর্ম্যাটে রূপান্তর করতে ব্যর্থ হয়েছিল।

আমি "পাইপ ইনস্টল সিম্পজসন" করেছি, তারপরে কেবল যুক্ত করে

import simplejson as json

সিরিয়ালাইজার এবং ডিসরিয়ালাইজার আবার purr শুরু করে। আমি অন্য কিছু করিনি ... ডিইসিএএমএলগুলি '234.00' ফ্ল্যাট ফর্ম্যাট হিসাবে প্রদর্শিত হবে।


1
সবচেয়ে সহজ ফিক্স
এসএমডিসি

1
অদ্ভুতভাবে যথেষ্ট, আপনি এমনকি আমদানি করতে হবে না simplejson- এটি ইনস্টল করা কৌশলটি করে does প্রাথমিকভাবে এই উত্তর দ্বারা উল্লিখিত ।
বিস্ফোরণ ২

এটি আমার উপর কাজ করে না এবং Decimal('0.00') is not JSON serializable এটি পাইপের মাধ্যমে ইনস্টল করার পরেও তা পেয়েছে । আপনি যখন মার্শমালো এবং গ্রাফিনি উভয় ব্যবহার করছেন তখন এই পরিস্থিতিটি হয়। বিশ্রাম এপিআই-তে যখন কোনও প্রশ্নের জিজ্ঞাসা করা হয়, মার্শম্যালো দশমিক ক্ষেত্রের জন্য প্রত্যাশিতভাবে কাজ করে। যাইহোক যখন এটি গ্রাফিক্যালে বলা হয় তখন এটি একটি is not JSON serializableত্রুটি বাড়িয়ে তোলে ।
রোল

চমত্কার, দুর্দান্ত,
স্পাইডারম্যান

পারফেক্ট! এটি এমন পরিস্থিতিতে কাজ করে যেখানে আপনি অন্য কারও দ্বারা লিখিত একটি মডিউল ব্যবহার করছেন যা আপনি সহজেই সংশোধন করতে পারবেন না (আমার ক্ষেত্রে গুগল শিটগুলি ব্যবহারের জন্য গুস্প্রেড)
হ্যাপিস্কেপটিক

32

আমি GAE 2.7 এর জন্য সিম্পজসন থেকে বিল্টিন জসনে স্যুইচ করার চেষ্টা করেছি এবং দশমিক নিয়ে সমস্যা ছিল। যদি ডিফল্ট আরআরটি ফিরে আসে (ও) সেখানে উদ্ধৃতিগুলি উপস্থিত ছিল (কারণ _iterencode কল _ _iterencode ডিফল্ট ফলাফলের উপর), এবং ভাসমান (ও) 0 টি অনুসরণ করে সরিয়ে ফেলবে।

যদি ডিফল্ট কোনও শ্রেণীর একটি বস্তু ফেরত দেয় যা ভাসা থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হয় (বা এমন কোনও কিছু যা অতিরিক্ত বিন্যাস ছাড়াই repr ডাকে) এবং একটি কাস্টম __repr__ পদ্ধতি থাকে তবে মনে হয় আমি এটি চাই যেমন কাজ করে।

import json
from decimal import Decimal

class fakefloat(float):
    def __init__(self, value):
        self._value = value
    def __repr__(self):
        return str(self._value)

def defaultencode(o):
    if isinstance(o, Decimal):
        # Subclass float with custom repr?
        return fakefloat(o)
    raise TypeError(repr(o) + " is not JSON serializable")

json.dumps([10.20, "10.20", Decimal('10.20')], default=defaultencode)
'[10.2, "10.20", 10.20]'

নিস! এটি নিশ্চিত করে যে দশমিক মানটি জাভাস্ক্রিপ্ট ফ্লোট হিসাবে জেএসএন-এ শেষ হবে, পাইথনটিকে এটি প্রথম দিকে নিকটতম ফ্লোট মান হিসাবে না নিয়েই।
কনরাড

3
দুর্ভাগ্যক্রমে এটি পাইথন 3 এর সাম্প্রতিক সময়ে কাজ করে না। এখন এমন কিছু ফাস্ট-পাথ কোড রয়েছে যা সমস্ত ফ্লোট-সাবক্লাসকে ভাসমান হিসাবে বিবেচনা করে এবং তাদের উপর সম্পূর্ণরূপে রিপ্রকে কল দেয় না।
অ্যান্টি হাপালা

অ্যান্টিহাপালা, উদাহরণটি পাইথন ৩.6-তে ভাল কাজ করে।
ক্রিশ্চিয়ান সিউপিতু

@ ক্রিশ্চিয়ানসিপিতু সত্যই, আমি এখন খারাপ আচরণটি পুনরুত্পাদন করতে সক্ষম বলে মনে হচ্ছে না
অ্যান্টি হাপালা

2
V3.5.2rc1 থেকে সমাধানটি কাজ করা বন্ধ করে দিয়েছে, github.com/python/cpython/commit/… দেখুন । নেই float.__repr__হার্ডকোডেড (যে স্পষ্টতা হারায়), এবং fakefloat.__repr__এ সব বলা হয় না। উপরের সমাধানটি পাইথন 3-এর 3.5.5.1 পর্যন্ত সঠিকভাবে কাজ করে, যদি ফেকফ্লোটের অতিরিক্ত পদ্ধতি থাকে def __float__(self): return self
মায়রোস্লাভ

30

নেটিভ বিকল্পটি অনুপস্থিত তাই আমি এটি পরবর্তী লোকের / গল এর জন্য যুক্ত করব it

জাজানো 1.7.x থেকে শুরু করে একটি বিল্ট-ইন রয়েছে DjangoJSONEncoderযা আপনি এটি থেকে পেতে পারেন django.core.serializers.json

import json
from django.core.serializers.json import DjangoJSONEncoder
from django.forms.models import model_to_dict

model_instance = YourModel.object.first()
model_dict = model_to_dict(model_instance)

json.dumps(model_dict, cls=DjangoJSONEncoder)

Presto!


যদিও এটি জানতে পেরে দুর্দান্ত, ওপি জ্যাঙ্গো সম্পর্কে জিজ্ঞাসা করেনি?
std''OrgnlDave 14

4
@ std''OrgnlDave আপনি 100% সঠিক আমি কীভাবে এখানে এসেছি তা ভুলে গিয়েছিলাম, তবে অনুসন্ধানের শব্দটির সাথে সংযুক্ত "জ্যাঙ্গো" দিয়ে আমি এই প্রশ্নটি গুগল করেছিলাম এবং এটি সামনে এসেছিল, আরও কিছুটা গুগল করার পরে, আমি উত্তরটি খুঁজে পেয়েছিলাম এবং আমার মতো পরবর্তী ব্যক্তির জন্য এখানে যুক্ত করেছি, যেগুলি হোঁচট খেয়ে পড়েছে এটি
জাভেয়ের বুজি

6
আপনি আমার দিন বাঁচান
gaozhidf 19'19

14

আমার 0 .02!

আমি আমার ওয়েব সার্ভারের জন্য প্রচুর পরিমাণে ডেটা সিরিয়ালাইজ করছি তাই আমি জেএসএন এনকোডারকে একগুচ্ছ প্রসারিত করি। এখানে কিছু সুন্দর কোড। মনে রাখবেন যে এটি সহজেই আপনার পছন্দ মতো কোনও ডেটা ফর্ম্যাটের কাছে প্রসারিত এবং এটি 3.9 হিসাবে পুনরুত্পাদন করবে"thing": 3.9

JSONEncoder_olddefault = json.JSONEncoder.default
def JSONEncoder_newdefault(self, o):
    if isinstance(o, UUID): return str(o)
    if isinstance(o, datetime): return str(o)
    if isinstance(o, time.struct_time): return datetime.fromtimestamp(time.mktime(o))
    if isinstance(o, decimal.Decimal): return str(o)
    return JSONEncoder_olddefault(self, o)
json.JSONEncoder.default = JSONEncoder_newdefault

আমার জীবনকে এত সহজ করে তোলে ...


3
এটি ভুল: এটি 3.9 হিসাবে পুনরুত্পাদন করবে "thing": "3.9"
গ্লাইফ

সকলের সর্বোত্তম সমাধান, খুব সহজ, ধন্যবাদ আপনি আমার দিনটি বাঁচিয়েছেন, আমার জন্য সংখ্যাটি বাঁচানোর জন্য যথেষ্ট, দশমিকের জন্য স্ট্রিং ঠিক আছে
স্ট্যাকডেভ

@ গ্লাইফ জেএসএন স্ট্যান্ডার্ডের মাধ্যমে (যার মধ্যে কয়েকটি ...), একটি অব্যক্ত সংখ্যা ডাবল-স্পষ্টতা ভাসমান-পয়েন্ট, দশমিক সংখ্যা নয়। এটিকে উদ্ধৃত করা সামঞ্জস্যতার নিশ্চয়তার একমাত্র উপায়।
std''OrgnlDave

2
আপনি কি এই জন্য একটি প্রশংসাপত্র আছে? আমি যে প্রতিটি স্পষ্ট পড়েছি তা বোঝায় এটি বাস্তবায়ন নির্ভর-
গ্লাইফ

12

3.9আইইইই ফ্লোটগুলিতে হুবহু উপস্থাপন করা যায় না, এটি সর্বদা আসবে যেমন 3.8999999999999999, উদাহরণস্বরূপ চেষ্টা করুন print repr(3.9), আপনি এটি সম্পর্কে এখানে আরও পড়তে পারেন:

http://en.wikedia.org/wiki/Floating_Point
http://docs.sun.com/source/806-3568/ncg_goldberg.html

সুতরাং আপনি যদি ভাসা না চান, কেবল বিকল্প আপনাকে এটিকে স্ট্রিং হিসাবে প্রেরণ করতে হবে এবং দশমিক অবজেক্টের স্বয়ংক্রিয়ভাবে জেএসএনে রূপান্তর করতে মঞ্জুরি দেওয়ার জন্য এই জাতীয় কিছু করুন:

import decimal
from django.utils import simplejson

def json_encode_decimal(obj):
    if isinstance(obj, decimal.Decimal):
        return str(obj)
    raise TypeError(repr(obj) + " is not JSON serializable")

d = decimal.Decimal('3.5')
print simplejson.dumps([d], default=json_encode_decimal)

আমি জানি এটি একবার ক্লায়েন্টে পার্স করার পরে এটি অভ্যন্তরীণভাবে 3.9 হবে না, তবে 3.9 একটি বৈধ জেএসএন ফ্ল্যাট। উদাহরণস্বরূপ, json.loads("3.9")কাজ করবে এবং আমি এটি হতে চাই
Knio

@ অনুরাগ আপনি আপনার উদাহরণে রেপ (ও) এর পরিবর্তে পুনরায় (আপত্তি) বোঝাতে চেয়েছিলেন।
orokusaki

দশমিক নয় এমন কিছু চেষ্টা করে এনকোড করে নিলেই কি এটি মারা যাবে না?
মাইকমেকানা

1
@ ননলার, না, আপনি এটি চেষ্টা করতে পারেন, কারণ হ্যান্ডলারটি ব্যবহার করা উচিত বলে সিগন্যাল দেওয়ার জন্য পূর্বনির্ধারিত ব্যতিক্রম বাড়াতে হবে
অনুরাগ ইউনিয়াল

1
মাইকেজ 302 এর উত্তর দেখুন - পাইথন ২.7 বা তারপরে, এটি আর প্রযোজ্য নয়।
জোয়েল ক্রস

9

জ্যাঙ্গো ব্যবহারকারীদের জন্য :

TypeError: Decimal('2337.00') is not JSON serializable জেএসএন এনকোডিংয়ের সময় সম্প্রতি এসেছিলjson.dumps(data)

সমাধান :

# converts Decimal, Datetime, UUIDs to str for Encoding
from django.core.serializers.json import DjangoJSONEncoder  

json.dumps(response.data, cls=DjangoJSONEncoder)

তবে, এখন দশমিক মানটি একটি স্ট্রিং হবে, এখন আমরা ডেটা ডিকোড করার সময় ডেসিমাল / ফ্লোট মান পার্সার স্পষ্টভাবে সেট করতে পারি, এতে parse_floatবিকল্পটি ব্যবহার করে json.loads:

import decimal 

data = json.loads(data, parse_float=decimal.Decimal) # default is float(num_str)

8

থেকে তাদেরকে JSON স্ট্যান্ডার্ড ডকুমেন্ট , সংযুক্ত হিসাবে json.org :

জেএসএন সংখ্যার শব্দার্থক সম্পর্কে অজ্ঞেয়বাদী। যে কোনও প্রোগ্রামিং ভাষায়, বিভিন্ন ধরণের বিভিন্ন ক্ষমতা এবং পরিপূরক, স্থির বা ভাসমান, বাইনারি বা দশমিক can যা বিভিন্ন প্রোগ্রামিং ভাষার মধ্যে আন্তঃ বিনিময় করতে পারে। JSON পরিবর্তে কেবলমাত্র সংখ্যার প্রতিনিধিত্ব করে যা মানুষ ব্যবহার করে: সংখ্যার ক্রম a সমস্ত প্রোগ্রামিং ল্যাঙ্গুয়েজগুলি অভ্যন্তরীণ উপস্থাপনায় একমত না হলেও কীভাবে ডিজিটিক সিক্যুয়েন্সটি বোঝায় তা জানে। বিনিময় অনুমতি দেওয়ার জন্য এটি যথেষ্ট।

সুতরাং ডেসিমালগুলি JSON এ সংখ্যার (স্ট্রিংয়ের পরিবর্তে) হিসাবে উপস্থাপন করা আসলেই সঠিক। বেলো সমস্যাটির একটি সম্ভাব্য সমাধান রয়েছে।

একটি কাস্টম JSON এনকোডার সংজ্ঞা দিন:

import json


class CustomJsonEncoder(json.JSONEncoder):

    def default(self, obj):
        if isinstance(obj, Decimal):
            return float(obj)
        return super(CustomJsonEncoder, self).default(obj)

তারপরে আপনার ডেটা সিরিয়াল করার সময় এটি ব্যবহার করুন:

json.dumps(data, cls=CustomJsonEncoder)

অন্যান্য উত্তরের মন্তব্যে যেমন উল্লেখ করা হয়েছে, অজগরের পুরানো সংস্করণগুলি ভাসমানে রূপান্তরিত করার সময় উপস্থাপনাটিকে বিশৃঙ্খলা করতে পারে, তবে সেটি আর হয় না।

পাইথনে দশমিক ফিরে পেতে:

Decimal(str(value))

দশমিকের উপর পাইথন 3.0 ডকুমেন্টেশনে এই সমাধানটির ইঙ্গিত দেওয়া হয়েছে :

একটি ভাসা থেকে দশমিক তৈরি করতে, প্রথমে এটি একটি স্ট্রিতে রূপান্তর করুন।


2
পাইথন 3 এ এটি "স্থির" নয় a float অগত্যা রূপান্তরকরণ আপনাকে দশমিক প্রতিনিধিত্ব হারাতে বাধ্য করে এবং তাত্পর্য সৃষ্টি করবে । যদি Decimalব্যবহার করা গুরুত্বপূর্ণ হয় তবে আমি মনে করি স্ট্রিংগুলি ব্যবহার করা ভাল।
juanpa.arrivillaga

আমি বিশ্বাস করি অজগর ৩.১ থেকে এটি করা নিরাপদ। গণিতের ক্রিয়াকলাপে নির্ভুলতার ক্ষতি ক্ষতিকারক হতে পারে, তবে জেএসএন এনকোডিংয়ের ক্ষেত্রে আপনি কেবলমাত্র মানটির স্ট্রিং ডিসপ্লে তৈরি করছেন, সুতরাং বেশিরভাগ ব্যবহারের ক্ষেত্রে যথাযথতা যথাযথের চেয়ে বেশি। জেএসএনের সমস্ত কিছু ইতিমধ্যে একটি স্ট্রিং, সুতরাং মানটির চারপাশে উদ্ধৃতি যুক্ত করা কেবল জেএসএন স্পেসকে অস্বীকার করে।
হুগো মোটা

এই বলে, আমি ভাসতে রূপান্তরিত করার আশেপাশের উদ্বেগগুলি বুঝতে পারি। পছন্দসই ডিসপ্লে স্ট্রিং উত্পাদন করতে এনকোডারটির সাথে ব্যবহার করার সম্ভবত আলাদা কৌশল আছে। তবুও, আমি মনে করি না এটি একটি উদ্ধৃত মান উত্পাদন মূল্য worth
হুগো মোটা

@ হুগোমোটা "জেএসএনের সমস্ত কিছু ইতিমধ্যে একটি স্ট্রিং, সুতরাং মূল্যটির চারপাশে উদ্ধৃতি স্থাপন করা জেএসওএন অনুমানকে অস্বীকার করে।" নং: rfc-editor.org/rfc/rfc8259.txt - জেএসএন একটি পাঠ্য-ভিত্তিক এনকোডিং ফর্ম্যাট, তবে এর অর্থ এই নয় যে এতে থাকা সমস্ত কিছুই স্ট্রিং হিসাবে ব্যাখ্যা করা উচিত। অনুমানটি স্ট্রিংগুলি থেকে পৃথক করে কীভাবে সংখ্যাগুলি এনকোড করা যায় তা নির্ধারণ করে।
গুন্নার আর ম্যাগনসন

@ গুন্নারম্যাগনেসন "জেএসএন হ'ল একটি পাঠ্য-ভিত্তিক এনকোডিং বিন্যাস" - এর অর্থ আমি "সবকিছুই একটি স্ট্রিং" বোঝাতে চাইছি। সংখ্যাগুলিকে আগেই স্ট্রিংয়ে রূপান্তর করা যাদুকরীভাবে যথার্থতা সংরক্ষণ করবে না কারণ এটি JSON হয়ে যাওয়ার পরে এটি কোনও স্ট্রিং হবে। এবং অনুমান অনুসারে, সংখ্যাগুলির চারপাশে কোট নেই। পড়ার সময় যথার্থতা সংরক্ষণ করার পাঠকের দায়িত্ব (কোনও উদ্ধৃতি নয়, কেবল আমার এটি গ্রহণ করুন)।
হুগো মোটা

6

আমার ক্লাস থেকে এটুকু পেয়েছি

class CommonJSONEncoder(json.JSONEncoder):

    """
    Common JSON Encoder
    json.dumps(myString, cls=CommonJSONEncoder)
    """

    def default(self, obj):

        if isinstance(obj, decimal.Decimal):
            return {'type{decimal}': str(obj)}

class CommonJSONDecoder(json.JSONDecoder):

    """
    Common JSON Encoder
    json.loads(myString, cls=CommonJSONEncoder)
    """

    @classmethod
    def object_hook(cls, obj):
        for key in obj:
            if isinstance(key, six.string_types):
                if 'type{decimal}' == key:
                    try:
                        return decimal.Decimal(obj[key])
                    except:
                        pass

    def __init__(self, **kwargs):
        kwargs['object_hook'] = self.object_hook
        super(CommonJSONDecoder, self).__init__(**kwargs)

যা ইউনিটেস্ট পাস করে:

def test_encode_and_decode_decimal(self):
    obj = Decimal('1.11')
    result = json.dumps(obj, cls=CommonJSONEncoder)
    self.assertTrue('type{decimal}' in result)
    new_obj = json.loads(result, cls=CommonJSONDecoder)
    self.assertEqual(new_obj, obj)

    obj = {'test': Decimal('1.11')}
    result = json.dumps(obj, cls=CommonJSONEncoder)
    self.assertTrue('type{decimal}' in result)
    new_obj = json.loads(result, cls=CommonJSONDecoder)
    self.assertEqual(new_obj, obj)

    obj = {'test': {'abc': Decimal('1.11')}}
    result = json.dumps(obj, cls=CommonJSONEncoder)
    self.assertTrue('type{decimal}' in result)
    new_obj = json.loads(result, cls=CommonJSONDecoder)
    self.assertEqual(new_obj, obj)

json.loads(myString, cls=CommonJSONEncoder)মন্তব্য হওয়া উচিতjson.loads(myString, cls=CommonJSONDecoder)
Kavaklıoğlu

অবজেক্ট দশমিক না হলে অবজেক্ট_হুকের একটি ডিফল্ট রিটার্ন মান দরকার।
Kavaklıoğlu

3

আপনি আপনার প্রয়োজন অনুসারে একটি কাস্টম JSON এনকোডার তৈরি করতে পারেন।

import json
from datetime import datetime, date
from time import time, struct_time, mktime
import decimal

class CustomJSONEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, datetime):
            return str(o)
        if isinstance(o, date):
            return str(o)
        if isinstance(o, decimal.Decimal):
            return float(o)
        if isinstance(o, struct_time):
            return datetime.fromtimestamp(mktime(o))
        # Any other serializer if needed
        return super(CustomJSONEncoder, self).default(o)

ডিকোডারটিকে এভাবে বলা যেতে পারে,

import json
from decimal import Decimal
json.dumps({'x': Decimal('3.9')}, cls=CustomJSONEncoder)

এবং আউটপুট হবে:

>>'{"x": 3.9}'

দুর্দান্ত ... এক স্টপ সমাধানের জন্য ধন্যবাদ (y)
মুহাম্মাদ বেসিল

এটি সত্যিই কাজ করে! আপনার সমাধান ভাগ করে নেওয়ার জন্য আপনাকে ধন্যবাদ
tthreetorch

3

যারা তৃতীয় পক্ষের গ্রন্থাগারটি ব্যবহার করতে চান না তাদের জন্য ... ইলিয়াস জামারিয়ার উত্তরের একটি সমস্যা হ'ল এটি ভাসতে রূপান্তরিত করে যা সমস্যার মধ্যে পড়তে পারে। উদাহরণ স্বরূপ:

>>> json.dumps({'x': Decimal('0.0000001')}, cls=DecimalEncoder)
'{"x": 1e-07}'
>>> json.dumps({'x': Decimal('100000000000.01734')}, cls=DecimalEncoder)
'{"x": 100000000000.01733}'

JSONEncoder.encode()পদ্ধতি আক্ষরিক JSON বিষয়বস্তু ফিরে অসদৃশ দেয় JSONEncoder.default(), যা আপনি (ভাসা মত) একটি JSON- সামঞ্জস্যপূর্ণ টাইপ আসতে হয়েছে যে তারপর স্বাভাবিক ভাবেই এনকোড পায়। সমস্যাটি encode()হ'ল এটি (সাধারণত) কেবলমাত্র শীর্ষ স্তরে কাজ করে। তবে এটি কিছুটা অতিরিক্ত কাজ (অজগর 3.x) সহ এখনও ব্যবহারযোগ্য:

import json
from collections.abc import Mapping, Iterable
from decimal import Decimal

class DecimalEncoder(json.JSONEncoder):
    def encode(self, obj):
        if isinstance(obj, Mapping):
            return '{' + ', '.join(f'{self.encode(k)}: {self.encode(v)}' for (k, v) in obj.items()) + '}'
        if isinstance(obj, Iterable) and (not isinstance(obj, str)):
            return '[' + ', '.join(map(self.encode, obj)) + ']'
        if isinstance(obj, Decimal):
            return f'{obj.normalize():f}'  # using normalize() gets rid of trailing 0s, using ':f' prevents scientific notation
        return super().encode(obj)

যা আপনাকে দেয়:

>>> json.dumps({'x': Decimal('0.0000001')}, cls=DecimalEncoder)
'{"x": 0.0000001}'
>>> json.dumps({'x': Decimal('100000000000.01734')}, cls=DecimalEncoder)
'{"x": 100000000000.01734}'

2

StdOrgnlDave উত্তরের ভিত্তিতে আমি এই মোড়কে সংজ্ঞায়িত করেছি যে এটি itচ্ছিক ধরণের মাধ্যমে বলা যেতে পারে যাতে এনকোডারটি কেবল আপনার প্রকল্পের ভিতরে নির্দিষ্ট ধরণের জন্য কাজ করতে পারে work আমি বিশ্বাস করি কাজটি আপনার কোডের ভিতরেই করা উচিত এবং এই "ডিফল্ট" এনকোডারটি ব্যবহার না করা থেকে "এটি অন্তর্নিহিতের চেয়ে ভাল স্পষ্টতাই", তবে আমি বুঝতে পারি এটি ব্যবহার করা আপনার কিছুটা সময় সাশ্রয় করবে। :-)

import time
import json
import decimal
from uuid import UUID
from datetime import datetime

def JSONEncoder_newdefault(kind=['uuid', 'datetime', 'time', 'decimal']):
    '''
    JSON Encoder newdfeault is a wrapper capable of encoding several kinds
    Use it anywhere on your code to make the full system to work with this defaults:
        JSONEncoder_newdefault()  # for everything
        JSONEncoder_newdefault(['decimal'])  # only for Decimal
    '''
    JSONEncoder_olddefault = json.JSONEncoder.default

    def JSONEncoder_wrapped(self, o):
        '''
        json.JSONEncoder.default = JSONEncoder_newdefault
        '''
        if ('uuid' in kind) and isinstance(o, uuid.UUID):
            return str(o)
        if ('datetime' in kind) and isinstance(o, datetime):
            return str(o)
        if ('time' in kind) and isinstance(o, time.struct_time):
            return datetime.fromtimestamp(time.mktime(o))
        if ('decimal' in kind) and isinstance(o, decimal.Decimal):
            return str(o)
        return JSONEncoder_olddefault(self, o)
    json.JSONEncoder.default = JSONEncoder_wrapped

# Example
if __name__ == '__main__':
    JSONEncoder_newdefault()

0

আপনি যদি requestsলাইব্রেরিতে দশমিকের সমন্বিত একটি অভিধান ( jsonকীওয়ার্ড আর্গুমেন্ট ব্যবহার করে ) পাস করতে চান তবে আপনার কেবল ইনস্টল করতে হবে simplejson:

$ pip3 install simplejson    
$ python3
>>> import requests
>>> from decimal import Decimal
>>> # This won't error out:
>>> requests.post('https://www.google.com', json={'foo': Decimal('1.23')})

সমস্যার কারণ হ'ল এটি উপস্থিত থাকলেই requestsব্যবহার করে simplejsonএবং jsonএটি ইনস্টল না থাকলে বিল্ট-ইন হয়ে পড়ে ।


-6

এটি যোগ করে করা যেতে পারে

    elif isinstance(o, decimal.Decimal):
        yield str(o)

ইন \Lib\json\encoder.py:JSONEncoder._iterencode, তবে আমি আরও ভাল সমাধানের আশা করছিলাম


5
আপনি উপরে বর্ণিত হিসাবে JSONEncoder সাবক্লাস করতে পারেন, একটি প্রতিষ্ঠিত লাইব্রেরির ইনস্টলড পাইথন ফাইলগুলি সম্পাদনা করা বা দোভাষী নিজেই খুব শেষ অবলম্বন হওয়া উচিত।
জাস্টানর
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.