I have a Console Application
with .NET 5
and IronPython 2.7.11
which uses Python 2.7
.
This is my code from C#:
Program.cs:
using System;
namespace IronPythonTest2
{
class Program
{
static void Main(string[] args)
{
Microsoft.Scripting.Hosting.ScriptRuntime scriptRuntime = null;
try
{
scriptRuntime = IronPython.Hosting.Python.CreateRuntime();
dynamic scriptModule = scriptRuntime.UseFile("test.py");
decimal decimalNumber = 1m / 3m;
scriptModule.print_decimal(decimalNumber);
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
finally
{
scriptRuntime.Shutdown();
}
}
}
}
test.py:
import locale
locale.setlocale(locale.LC_NUMERIC, 'en_US')
from decimal import *
def print_decimal(system_decimal):
print(convert_to_decimal(system_decimal))
print(convert_to_decimal_locale(system_decimal))
def convert_to_decimal(system_decimal):
return Decimal(str(system_decimal))
def convert_to_decimal_locale(system_decimal):
return Decimal(locale.format_string('%.28f', system_decimal))
This is my Project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IronPython" Version="2.7.11" />
<PackageReference Include="IronPython.StdLib" Version="2.7.11" />
</ItemGroup>
</Project>
output:
0.3333333333333333333333333333
0.3333333333333333703407674875
Question 1: Why they are different outputs?
The reason I'm using locale
is that the convert_to_decimal
function will throw the exception: "Invalid literal for Decimal" if that runs in a computer with a different culture which uses a comma "," instead of a dot "." for decimals.
I also noticed that the python Decimal
does NOT accept comma ",", so by using locale
I managed to fix it, however I want to keep all decimal places when using locale.format_string
.
Question 2: Instead of passing a hardcoded string format like %.28f
how to pass a specific format to display all decimal places something like e.g. '%d.%d'
so it wouldn't need to specify the .28f
part. How to do that?
EDIT
As @UlrichEckhardt has mentioned on his comment, I'm providing a minimal reproducible example for python users.
import locale
from decimal import *
def print_decimal(system_decimal):
print(convert_to_decimal(system_decimal))
print(convert_to_decimal_locale(system_decimal))
def convert_to_decimal(system_decimal):
return Decimal(str(system_decimal))
def convert_to_decimal_locale(system_decimal):
return Decimal(locale.format_string('%.28f', system_decimal))
def main():
print_decimal(Decimal('1') / Decimal('3'))
if __name__ == "__main__":
main()
output is slightly different from the Original Post though:
0.3333333333333333333333333333
0.3333333333333333148296162562
EDIT 2
As @tripleee answer suggests, the locale.str()
seems to partially solve the problem since setting the locale to 'en_US'
makes it replace the comma "," by the dot "." in a computer with such a culture, so python Decimal
accepted it. However getcontext().prec = 28
didn't seem to work, it prints 12 decimal places. I'm not sure if I applied it correctly in my code, so here's it:
import locale
locale.setlocale(locale.LC_NUMERIC, 'en_US')
from decimal import *
getcontext().prec = 28
def print_decimal(system_decimal):
print(convert_to_decimal(system_decimal))
print(convert_to_decimal_locale(system_decimal))
def convert_to_decimal(system_decimal):
return Decimal(str(system_decimal))
def convert_to_decimal_locale(system_decimal):
return Decimal(locale.str(system_decimal))
Just a reminder that I'm testing it on 2 computers, one with en_US
culture and another with pt_BR
culture. The convert_to_decimal_locale
function is intended to be used when pt_BR
culture is present otherwise it would get the Invalid literal for Decimal exception since python Decimal
does NOT support commas for decimals. So this output is from a computer with en_US
culture, if you're going to use that code in another computer with culture e.g. which uses a comma "," for decimals so comment the #print(convert_to_decimal(system_decimal))
line otherwise you're gonna get the mentioned exception.
output:
0.3333333333333333333333333333
0.333333333333