skip to Main Content

I am using ipython 5.8.0 on Debian 10.

This is how output looks like:

In [1]: 50*50
Out[1]: 2500

Is it possible to configure ipython to print all numbers with thousands separators? ie:

In [1]: 50*50
Out[1]: 2'500

In [2]: 5000*5000
Out[2]: 25'000'000

And perhaps, is it possible to make ipython also understand thousands separators on input?

In [1]: 5'000*5'000
Out[1]: 25'000'000

UPDATE

The accepted answer from @Chayim Friedman works for integers, but does not work for float:

In [1]: 500.1*500
Out[1]: 250050.0

Also, when it works, it uses , as the character for thousand separator:

In [1]: 500*500
Out[1]: 250,000

Can I use ' instead?

4

Answers


  1. After update: you can subclass int:

    class Int(int):
        def __repr__(self):
            return "{:,}".format(self)
    Int(1000)
    # 1,000
    
    Login or Signup to reply.
  2. I don’t believe you can achieve all that you are looking for without rewriting the iPython interpreter, which means changing the Python language specification, to be able to input numbers with embedded ' characters and have them ignored. But you can achieve some of it. Subclassing the int class is a good start. But you should also overload the various operators you plan on using. For example:

    class Integer(int):
        def __str__(self):
            # if you want ' as the separator:
            return "{:,}".format(self).replace(",", "'")
    
        def __add__(self, x):
            return Integer(int(self) + x)
    
        def __mul__(self, x):
            return Integer(int(self) * x)
    
        """
        define other operations: __sub__, __floordiv__, __mod__, __neg__, etc.
        """
    
    
    i1 = Integer(2)
    i2 = Integer(1000) + 4.5 * i1
    print(i2)
    print(i1 * (3 + i2))
    

    Prints:

    1'009
    2'024
    

    Update

    It seems that for Python 3.7 you need to override the __str__ method rather than the __repr__ method. This works for Python 3.8 and should work for later releases as well.

    Update 2

    import locale
    
    #locale.setlocale(locale.LC_ALL, '') # probably not required
    print(locale.format_string("%d", 1255000, grouping=True).replace(",", "'"))
    

    Prints:

    1'255'000
    

    An alternative if you have package Babel from the PyPi repository:

    from babel import Locale
    from babel.numbers import format_number
    
    locale = Locale('en', 'US')
    locale.number_symbols['group'] = "'"
    
    print(format_number(1255000, locale='en_US'))
    

    Prints:

    1'255'000
    

    Or if you prefer to custom-tailor a locale just for this purpose and leave the standard en_US locale unmodified. This also shows how you can parse input values:

    from copy import deepcopy
    from babel import Locale
    from babel.numbers import format_number, parse_number
    
    my_locale = deepcopy(Locale('en', 'US'))
    my_locale.number_symbols['group'] = "'"
    print(format_number(1255000, locale=my_locale))
    print(parse_number("1'125'000", locale=my_locale))
    

    Prints:

    1'255'000
    1125000
    
    Login or Signup to reply.
  3. Based on PEP-0378, you can use the following code:

    a = 1200
    b = 500
    c = 10
    
    #res = a
    #res = a*b
    res = a*b*c
    
    dig = len(str(res))       # to figure out how many digits are required in result
    print(format(res, "{},d".format(dig)))
    

    It will produce:

    6,000,000
    
    Login or Signup to reply.
  4. Using ' as thousands separator in input is quite problematic because Python uses ' to delimit strings, but you can use _ (PEP 515, Underscores in Numeric Literals):

    IPython input thousand separators

    Regarding output, this is slightly harder, but can be done using IPython extensions.

    Put the following Python code in a new file at ~/.ipython/extensions/thousands_separator.py:

    default_int_printer = None
    
    def print_int(number, printer, cycle):
        printer.text(f'{number:,}') # You can use `'{:,}'.format(number)` if you're using a Python version older than 3.6
    
    def load_ipython_extension(ipython):
        global default_int_printer
    
        default_int_printer = ipython.display_formatter.formatters['text/plain'].for_type(int, print_int)
    
    def unload_ipython_extension(ipython):
        ipython.display_formatter.formatters['text/plain'].for_type(int, default_int_printer)
    

    This code tells IPython to replace the default int formatter with one that prints thousand separators when this extension is loaded, and restore the original when it is unloaded.

    Edit: If you want a different separator, for instance ', replace the f'{number:,}' with f'{number:,}'.replace(',', "'").

    You can load the extension using the magic command %load_ext thousands_separator and unload it using %unload_ext thousands_separator, but if you want it always, you can place it in the default profile.

    Run the following code in the terminal:

    ipython3 profile create
    

    It will report that a file ~/.ipython/profile_default/ipython_config.py was created. Enter it, and search for the following string:

    ## A list of dotted module names of IPython extensions to load.
    #c.InteractiveShellApp.extensions = []
    

    Replace it with the following:

    # A list of dotted module names of IPython extensions to load.
    c.InteractiveShellApp.extensions = [
        'thousands_separator'
    ]
    

    This tells IPython to load this extension by default.

    Done!

    enter image description here

    Edit: I saw that you want to a) use ' as separator, and b) do the same for floats:

    Using different separator is quite easy: just str.replace():

    def print_int(number, printer, cycle):
        printer.text(f'{number:,}'.replace(',', "'"))
    

    Doing the same for floats is also easy: just setup print_int so it prints floats to. I also suggest to change the name to print_number.

    Final code:

    default_int_printer = None
    default_float_printer = None
    
    def print_number(number, printer, cycle):
        printer.text(f'{number:,}'.replace(',', "'"))
    
    def load_ipython_extension(ipython):
        global default_int_printer
        global default_float_printer
    
        default_int_printer = ipython.display_formatter.formatters['text/plain'].for_type(int, print_number)
        default_float_printer = ipython.display_formatter.formatters['text/plain'].for_type(float, print_number)
    
    def unload_ipython_extension(ipython):
        ipython.display_formatter.formatters['text/plain'].for_type(int, default_int_printer)
        ipython.display_formatter.formatters['text/plain'].for_type(float, default_float_printer)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search