YAML loads 5e-6 as string and not a number

2024/11/20 4:28:01

When I load a number with e form a JSON dump with YAML, the number is loaded as a string and not a float.

I think this simple example can explain my problem.

import json
import yamlIn [1]: import jsonIn [2]: import yamlIn [3]: All = {'one':1,'low':0.000001}In [4]: jAll = json.dumps(All)In [5]: yAll = yaml.safe_load(jAll)In [6]: yAll
Out[6]: {'low': '1e-06', 'one': 1}

YAML loads 1e-06 as a string and not as a number? How can I fix it?

Answer

The problem lies in the fact that the YAML Resolver is set up to match floats as follows:

Resolver.add_implicit_resolver(u'tag:yaml.org,2002:float',re.compile(u'''^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?|\\.[0-9_]+(?:[eE][-+][0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$''', re.X),list(u'-+0123456789.'))

whereas the YAML spec specifies the regex for scientific notation as:

-? [1-9] ( \. [0-9]* [1-9] )? ( e [-+] [1-9] [0-9]* )?

the latter makes the dot optional, which it isn't in the above re.compile() pattern in the implicit resolver.

The matching of floats can be fixed so it will accept floating point values with an e/E but without decimal dot and with exponents without sign (i.e. + implied):

import yaml
import json
import reAll = {'one':1,'low':0.000001}jAll = json.dumps(All)loader = yaml.SafeLoader
loader.add_implicit_resolver(u'tag:yaml.org,2002:float',re.compile(u'''^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?|[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)|\\.[0-9_]+(?:[eE][-+][0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$''', re.X),list(u'-+0123456789.'))data = yaml.load(jAll, Loader=loader)
print 'data', data

results in:

data {'low': 1e-06, 'one': 1}

There is discrepancy between what JSON allows in numbers and the regex in the YAML 1.2 spec (concerning the required dot in the number and e being lower case). The JSON specification is IMO very clear in that it doesn't require the dot before 'e/E' nor that is requires a sign after the 'e/E':

enter image description here

The PyYAML implementation does match floats partially according to the JSON spec and partially against the regex and fails on numbers that should be valid.

ruamel.yaml (which is my enhanced version of PyYAML), has these updated pattern and works correctly:

import ruamel.yaml
import jsonAll = {'one':1,'low':0.000001}jAll = json.dumps(All)data = ruamel.yaml.load(jAll)
print 'data', data

with output:

data {'low': 1e-06, 'one': 1}

ruamel.yaml also accepts the number '1.0e6', which PyYAML also sees as a string.

https://en.xdnf.cn/q/26359.html

Related Q&A

How to get rid of grid lines when plotting with Seaborn + Pandas with secondary_y

Im plotting two data series with Pandas with seaborn imported. Ideally I would like the horizontal grid lines shared between both the left and the right y-axis, but Im under the impression that this is…

How to set the line width of error bar caps

How can the line width of the error bar caps in Matplotlib be changed?I tried the following code:(_, caplines, _) = matplotlib.pyplot.errorbar(data[distance], data[energy], yerr=data[energy sigma],cap…

Where is Pythons shutdown procedure setting module globals to None documented?

CPython has a strange behaviour where it sets modules to None during shutdown. This screws up error logging during shutdown of some multithreading code Ive written.I cant find any documentation of this…

Save a dictionary to a file (alternative to pickle) in Python?

Answered I ended up going with pickle at the end anywayOk so with some advice on another question I asked I was told to use pickle to save a dictionary to a file. The dictionary that I was trying to sa…

python equivalent of functools partial for a class / constructor

I want to create a class that behaves like collections.defaultdict, without having the usage code specify the factory. EG: instead of class Config(collections.defaultdict):passthis:Config = functools.p…

Set the font size in pycharms python console or terminal

There are terminal and python console in pycharm, which are very convenient. But I found that the font size was too small to recognize in terminal or python console. How can change the font size in the…

How to filter model results for multiple values for a many to many field in django

I have the following Model:class Group(models.Model):member = models.ManyToManyField(Player, through=GroupMember)name = models.CharField(max_length=20, unique=True)join_password = models.CharField(max_…

Why is string comparison so fast in python?

I became curious to understand the internals of how string comparison works in python when I was solving the following example algorithm problem:Given two strings, return the length of the longest comm…

What is a namespace object?

import argparseparser = argparse.ArgumentParser(description=sort given numbers) parser.add_argument(-s, nargs = +, type = int) args = parser.parse_args() print(args)On command line when I run the comma…

How to get the element-wise mean of an ndarray

Id like to calculate element-wise average of numpy ndarray.In [56]: a = np.array([10, 20, 30])In [57]: b = np.array([30, 20, 20])In [58]: c = np.array([50, 20, 40])What I want:[30, 20, 30]Is there any …