Impressão fácil e bonita de flutuadores em python?

93

Eu tenho uma lista de carros alegóricos. Se eu simplesmente fizer printisso, aparecerá assim:

[9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999, 0.055702500000000002, 0.079330300000000006]

Eu poderia usar print "%.2f", o que exigiria um forloop para percorrer a lista, mas não funcionaria para estruturas de dados mais complexas. Eu gostaria de algo como (estou completamente inventando)

>>> import print_options
>>> print_options.set_float_precision(2)
>>> print [9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999, 0.055702500000000002, 0.079330300000000006]
[9.0, 0.05, 0.03, 0.01, 0.06, 0.08]
static_rtti
fonte

Respostas:

23

É uma pergunta antiga, mas eu acrescentaria algo potencialmente útil:

Eu sei que você escreveu seu exemplo em listas Python brutas, mas se você decidir usar numpyarrays (o que seria perfeitamente legítimo em seu exemplo, porque você parece estar lidando com arrays de números), há (quase exatamente) este comando que você disse que você inventou:

import numpy as np
np.set_printoptions(precision=2)

Ou ainda melhor no seu caso, se você ainda quiser ver todos os decimais de números realmente precisos, mas se livrar dos zeros à direita, por exemplo, use a string de formatação %g:

np.set_printoptions(formatter={"float_kind": lambda x: "%g" % x})

Para imprimir apenas uma vez e não alterar o comportamento global, use np.array2stringcom os mesmos argumentos acima.

PlasmaBinturong
fonte
102

Como ninguém o adicionou, deve-se notar que, partindo do Python 2.6+, a maneira recomendada de fazer a formatação de strings é com format, se preparar para o Python 3+.

print ["{0:0.2f}".format(i) for i in a]

A nova sintaxe de formatação de strings não é difícil de usar e, ainda assim, é bastante poderosa.

Achei que pprintpoderia ter algo, mas não encontrei nada.

Esteban Küber
fonte
1
Este foi o que usei, mas adicionei .replace("'", "")para me livrar das vírgulas. str(["{0:0.2f}".format(i) for i in a]).replace("'", "")
Steinarr Hrafn Höskuldsson
Isso produzirá uma lista de strings. Na saída impressa, cada elemento tem ''ao seu redor. Por exemplo, para a=[0.2222, 0.3333], ele vai produzir ['0.22', '0.33'].
jdhao
Para remover o vértice e as vírgulas, você deve usar' '.join([{0:0.2f}".format(i) for i in a])
Neb
78

Uma solução mais permanente é criar uma subclasse float:

>>> class prettyfloat(float):
    def __repr__(self):
        return "%0.2f" % self

>>> x
[1.290192, 3.0002, 22.119199999999999, 3.4110999999999998]
>>> x = map(prettyfloat, x)
>>> x
[1.29, 3.00, 22.12, 3.41]
>>> y = x[2]
>>> y
22.12

O problema com a criação de subclasses floaté que ela quebra o código que está procurando explicitamente o tipo de uma variável. Mas, pelo que posso dizer, esse é o único problema com isso. E um simples x = map(float, x)desfaz a conversão para prettyfloat.

Tragicamente, você não pode simplesmente corrigir o problema float.__repr__, porque floaté imutável.

Se você não quer criar uma subclasse float, mas não se importa em definir uma função, map(f, x)é muito mais conciso do que[f(n) for n in x]

Robert Rossney
fonte
Eu teria pensado que havia uma solução mais simples, mas sua resposta é claramente a melhor, já que você foi o único que realmente respondeu à minha pergunta.
static_rtti
4
Ele é o único a realmente responder à sua pergunta-editada. Não deprecie o respondente, mas você não pode esclarecer uma pergunta e depois desprezar o restante dos respondentes com base nas informações com as quais estávamos trabalhando.
Jed Smith,
1
Minha pergunta original mencionou que eu considerava um loop for não uma boa solução (para mim, a compreensão de uma lista é a mesma, mas concordo que não estava claro). Vou tentar ser mais claro da próxima vez.
static_rtti
2
[f (n) para n em x] é muito mais pythônico do que map (f, x).
Robert T. McGibbon
2
Não sou necessariamente a favor da subclasse de float, mas não acho que a verificação de tipo seja um argumento válido. Ao verificar os tipos, isinstancedeve ser usado, não a igualdade de type(). Quando feito corretamente, uma subclasse de float ainda será contada como um float.
zondo
37

Você pode fazer:

a = [9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999, 0.055702500000000002, 0.079330300000000006]
print ["%0.2f" % i for i in a]
Pablo Santa Cruz
fonte
3
Isso imprimirá ['9,00', '0,05', '0,03', '0,01', '0,06', '0,08'] - com aspas, o que você geralmente não quer (eu prefiro ter uma lista válida de flutuantes impresso)
Emile
23

Observe que você também pode multiplicar uma string como "% .2f" (exemplo: "% .2f" * 10).

>>> print "%.2f "*len(yourlist) % tuple(yourlist)
2.00 33.00 4.42 0.31 
dalloliogm
fonte
3
muito elegante! Eu gosto disso
Nathan Fellman
2
-1 hack terrível. Junte pedaços formatados de strings, não o contrário, por favor
u0b34a0f6ae
1
então kaizer.se, você está propondo "" .join (["%. 2f"% x para x em sua lista]). Eu tenho que fazer esse tipo de construção em python.
Gregg Lind,
sim, eu proponho, " ".join("%.2f" % x for x in yourlist)já que separar string de formato e valores de interpolação é muito pior do que usar uma linguagem feia de Python.
u0b34a0f6ae
É curiosidade. Por que a tupla está funcionando enquanto a lista falha? Sem "tupla", comete erro. Por quê?
Joonho Park
8
print "[%s]"%", ".join(map(str,yourlist))

Isso evitará os erros de arredondamento na representação binária quando impressa, sem introduzir uma restrição de precisão fixa (como formatação com "%.2f"):

[9.0, 0.053, 0.0325754, 0.0108928, 0.0557025, 0.0793303]
Fortran
fonte
7
l = [9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999, 0.055702500000000002, 0.079330300000000006]

Python 2:

print ', '.join('{:0.2f}'.format(i) for i in l)

Python 3:

print(', '.join('{:0.2f}'.format(i) for i in l))

Resultado:

9.00, 0.05, 0.03, 0.01, 0.06, 0.08
Chikipowpow
fonte
Não sei por que isso não é maior. Uma solução que não depende de bibliotecas de terceiros!
Fl.pf.
7

A opção mais fácil deve ser usar uma rotina de arredondamento:

import numpy as np
x=[9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999, 0.055702500000000002, 0.079330300000000006]

print('standard:')
print(x)
print("\nhuman readable:")
print(np.around(x,decimals=2))

Isso produz a saída:

standard:
[9.0, 0.053, 0.0325754, 0.0108928, 0.0557025, 0.0793303]

human readable:
[ 9.    0.05  0.03  0.01  0.06  0.08]
Markus Dutschke
fonte
esta é uma ótima resposta
jjz
4

Eu acredito que o Python 3.1 irá imprimi-los melhor por padrão, sem qualquer alteração no código. Mas isso é inútil se você usar qualquer extensão que não tenha sido atualizada para funcionar com Python 3.1

Echo diz Reintegrar Monica
fonte
1
Python 3.1 imprimirá a representação decimal mais curta que mapeia para esse valor flutuante. Por exemplo: >>> a, b = float (1.1), float (1.1000000000000001) >>> a 1.1000000000000001 >>> b 1.1000000000000001 >>> print (a, b) 1.1 1.1
Matt Boehm
4

Os comps da lista são seus amigos.

print ", ".join("%.2f" % f for f in list_o_numbers)

Tente:

>>> nums = [9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999]
>>> print ", ".join("%.2f" % f for f in nums)
9.00, 0.05, 0.03, 0.01
Jed Smith
fonte
5
Uma expressão geradora seria ainda melhor: "," .join ("%. 2f"% f for f em list_o_numbers)
efotinis
@efotinis Ainda não adicionei isso ao meu repertório, mas você está certo - isso é muito sexy.
Jed Smith,
1
@Jed: Por favor, leia o FAQ, seção "Outras pessoas podem editar minhas coisas ?!": stackoverflow.com/faq . Nem toda edição é boa, mas esta foi uma melhoria genuína. Talvez você possa listar as duas técnicas em sua resposta e adicionar uma observação sobre a diferença.
Stephan202 de
4

Para controlar o número de dígitos significativos , use o especificador de formato% g.

Vamos nomear a solução de Emile como prettylist2f. Aqui está o modificado:

prettylist2g = lambda l : '[%s]' % ', '.join("%.2g" % x for x in l)

Uso:

>>> c_e_alpha_eps0 = [299792458., 2.718281828, 0.00729735, 8.8541878e-12]
>>> print(prettylist2f(c_e_alpha_eps0)) # [299792458.00, 2.72, 0.01, 0.00]
>>> print(prettylist2g(c_e_alpha_eps0)) # [3e+08, 2.7, 0.0073, 8.9e-12]

Se você quiser flexibilidade no número de dígitos significativos, use a formatação de string f em seu lugar:

prettyflexlist = lambda p, l : '[%s]' % ', '.join(f"{x:.{p}}" for x in l)
print(prettyflexlist(3,c_e_alpha_eps0)) # [3e+08, 2.72, 0.0073, 8.85e-12]
Rainald62
fonte
3

Você pode usar pandas.

Aqui está um exemplo com uma lista:

In: import pandas as P
In: P.set_option('display.precision',3)
In: L = [3.4534534, 2.1232131, 6.231212, 6.3423423, 9.342342423]
In: P.Series(data=L)
Out: 
0    3.45
1    2.12
2    6.23
3    6.34
4    9.34
dtype: float64

Se você tiver um ditado e quiser suas chaves como linhas:

In: d
Out: {1: 0.453523, 2: 2.35423234234, 3: 3.423432432, 4: 4.132312312}

In: P.DataFrame(index=d.keys(), data=d.values())
Out:  
    0
1   0.45
2   2.35
3   3.42
4   4.13

E outra maneira de dar ditado a um DataFrame:

P.DataFrame.from_dict(d, orient='index')
Ifmihai
fonte
2

Primeiro, os elementos dentro de uma coleção imprimem sua repr. você deve aprender sobre __repr__e __str__.

Esta é a diferença entre print repr (1.1) e print 1.1. Vamos juntar todas essas strings em vez das representações:

numbers = [9.0, 0.053, 0.0325754, 0.0108928, 0.0557025, 0.07933]
print "repr:", " ".join(repr(n) for n in numbers)
print "str:", " ".join(str(n) for n in numbers)
u0b34a0f6ae
fonte
NOTA: No Python 2.7, para este exemplo, os resultados da linha "repr" e da linha "str" ​​são idênticos.
Toolmaker Steve
2

Acabei de ter esse problema ao tentar usar o pprint para gerar uma lista de tuplas de flutuantes. Compreensões aninhadas podem ser uma má ideia, mas eis o que fiz:

tups = [
        (12.0, 9.75, 23.54),
        (12.5, 2.6, 13.85),
        (14.77, 3.56, 23.23),
        (12.0, 5.5, 23.5)
       ]
pprint([['{0:0.02f}'.format(num) for num in tup] for tup in tups])

Usei expressões de gerador no início, mas pprint apenas repred o gerador ...

kitsu.eb
fonte
2

A partir do Python 3.6, você pode usar strings f:

list_ = [9.0, 0.052999999999999999, 
         0.032575399999999997, 0.010892799999999999, 
         0.055702500000000002, 0.079330300000000006]

print(*[f"{element:.2f}" for element in list_])
#9.00 0.05 0.03 0.01 0.06 0.08

Você pode usar parâmetros de impressão enquanto mantém o código muito legível:

print(*[f"{element:.2f}" for element in list_], sep='|', end='<--')
#9.00|0.05|0.03|0.01|0.06|0.08<--
x0s
fonte
1

Eu tive esse problema, mas nenhuma das soluções aqui fez exatamente o que eu queria (quero que a saída impressa seja uma expressão Python válida), então que tal:

prettylist = lambda l : '[%s]' % ', '.join("%.2f" % f for f in l)

Uso:

>>> ugly = [9.0, 0.052999999999999999, 0.032575399999999997,
            0.010892799999999999, 0.055702500000000002, 0.079330300000000006]
>>> prettylist = lambda l : '[%s]' % ', '.join("%.2f" % f for f in l)
>>> print prettylist(ugly)
[9.00, 0.05, 0.03, 0.01, 0.06, 0.08]

(Eu sei que .format () deve ser a solução mais padrão, mas acho isso mais legível)

Emile
fonte
0

Eu concordo com o comentário do SilentGhost, o loop for não é tão ruim assim. Você pode conseguir o que deseja com:

l = [9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999, 0.055702500000000002, 0.079330300000000006]
for x in l: print "%0.2f" % (x)
PTBNL
fonte
3
Embora os loops for não sejam feios, esse uso não é terrivelmente pitônico.
Jed Smith,
-1

O código abaixo funciona bem para mim.

list = map (lambda x: float('%0.2f' % x), list)
Romerito
fonte