p vs põe em Ruby

270

Existe alguma diferença entre pe putsno Ruby?

collimarco
fonte

Respostas:

334

p fooimprime foo.inspectseguido por uma nova linha, ou seja, imprime o valor de em inspectvez de to_s, o que é mais adequado para depuração (porque você pode, por exemplo, diferenciar entre 1, "1"e "2\b1", o que não pode ao imprimir sem inspect).

sepp2k
fonte
7
Yep, p (e puts) estão ambos no módulo Kernel para que você possa ver os detalhes aqui: ruby-doc.org/core/classes/Kernel.html#M005961
MikeJ
17
Observe que ptambém retorna o valor do objeto, enquanto putsnão retorna . 1.9.3p125 :002 > (p "foo").class "foo" => String 1.9.3p125 :003 > (puts "foo").class foo => NilClass
Darren Cheng
2
Grande resumo fornecido por Gareth Rees em seu post intitulado "Ruby p vs puts vs print" .
Alexanderjsingleton
Meio que sinto que isso me deixa com uma toca de perguntas. O que é inspecionar? O que é to_s? Por que desejo inspecionar o texto impresso em vez de uma variável? Qual é o padrão para o mundo da programação, devido à sua menção de depuração, p ou puts? Todos os "p" devem ser substituídos por "puts" após a conclusão da depuração? Vejo, em um comentário acima, que p retorna um objeto, o que é uma enorme diferença. Não tenho certeza se essa resposta está completa se ela mencionar apenas uma pequena diferença que levará a perguntas maiores que ainda meio que respondem à pergunta original.
1
@AaronLoften to_sé o método padrão de string em Ruby. inspect. como eu disse, é um método alternativo para string, que produz uma saída mais adequada para depuração. Após a conclusão da depuração, você obviamente deve remover suas instruções de depuração (ou, para projetos mais sérios, você provavelmente deve usar uma estrutura de log e não usar p ou puts para depuração). O fato de pretornar o objeto parece irrelevante na maioria das situações (e acredito que dei essa resposta antes que isso acontecesse). A diferença na saída é a principal diferença (e costumava ser a única).
sepp2k
54

Também é importante notar que puts"reage" a uma classe que to_sdefiniu, pnão. Por exemplo:

class T
   def initialize(i)
      @i = i
   end
   def to_s
      @i.to_s
   end
end

t = T.new 42
puts t   => 42
p t      => #<T:0xb7ecc8b0 @i=42>

Isso segue diretamente da .inspectchamada, mas na prática não é óbvio.

ezpz
fonte
37

p foo é o mesmo que puts foo.inspect

August Lilleaas
fonte
4
mas putsretorna nil, em vez de foocomo faz p.
Ribamar
10
Isto é errado. É o mesmo queputs foo.inspect; foo
Eric Duminil
Isso prova que você está resposta é incorreta: (-> {p "Hello World"}.call) == (-> {puts "Hello World".inspect}.call ) . Muitos upvotes NÃO fazem disso uma boa resposta!
precisa
3

Além das respostas acima, há uma diferença sutil na saída do console - a presença / ausência de vírgulas / aspas invertidas - que pode ser útil:

p "+++++"
>> "+++++"

puts "====="
>> =====

Acho isso útil se você quiser fazer uma barra de progresso simples, usando o parente próximo deles, print :

array = [lots of objects to be processed]
array.size
>> 20

Isso fornece a barra de progresso de 100%:

puts "*" * array.size
>> ********************

E isso adiciona um * incremental em cada iteração:

array.each do |obj|
   print "*"
   obj.some_long_executing_process
end

# This increments nicely to give the dev some indication of progress / time until completion
>> ******
Jonathan_W
fonte
2

De documento ruby-2.4.1

coloca

puts(obj, ...) → nil

Grava o (s) objeto (s) fornecido (s) no ios. Grava uma nova linha após qualquer uma que ainda não termine com uma sequência de nova linha. Retorna nulo .

O fluxo deve ser aberto para gravação. Se chamado com um argumento de matriz , grava cada elemento em uma nova linha. Cada objeto que não é uma string ou matriz será convertido chamando seu to_s método. Se chamado sem argumentos, gera uma única nova linha.

vamos tentar no irb

# always newline in the end 
>> puts # no arguments

=> nil # return nil and writes a newline
>> puts "sss\nsss\n" # newline in string
sss
sss
=> nil
>> puts "sss\nsss" # no newline in string
sss
sss
=> nil

# for multiple arguments and array
>> puts "a", "b"
a
b
=> nil
>> puts "a", "b", ["c", "d"]
a
b
c
d
=> nil

p

p(obj) → obj click to toggle source
p(obj1, obj2, ...) → [obj, ...] p() → nil
Para cada objeto, as gravações diretamente são obj.inspectseguidas por uma nova linha na saída padrão do programa.

no irb

# no arguments
>> p
=> nil # return nil, writes nothing
# one arguments
>> p "sss\nsss\n" 
"sss\nsss\n"
=> "aaa\naaa\n"
# multiple arguments and array
>> p "a", "b"
"a"
"b"
=> ["a", "b"] # return a array
>> p "a", "b", ["c", "d"]
"a"
"b"
["c", "d"]
=> ["a", "b", ["c", "d"]] # return a nested array
fangxing
fonte
0

Estes 2 são iguais:

p "Hello World"  
puts "Hello World".inspect

( inspecionar fornece uma visão mais literal do objeto em comparação com o método to_s )

apadana
fonte
eles parecem iguais, mas não são. Experimente:(->{p "Hello World"}.call) == (-> {puts "Hello World".inspect}.call )
lacostenycoder
0

Isso pode ilustrar uma das principais diferenças, que é que pretorna o valor do que é passado para ele, onde é putsretornado nil.

def foo_puts
  arr = ['foo', 'bar']
  puts arr
end

def foo_p
  arr = ['foo', 'bar']
  p arr
end

a = foo_puts
=>nil
a
=>nil

b = foo_p
=>['foo', 'bar']
b
['foo', 'bar']

O benchmark mostra que putsé mais lento

require 'benchmark'
str = [*'a'..'z']
str = str*100
res = Benchmark.bm do |x|
  x.report(:a) { 10.times {p str} }
  x.report(:b) { 10.times {puts str} }
end
puts "#{"\n"*10}"
puts res

0.010000   0.000000   0.010000 (  0.047310)
0.140000   0.090000   0.230000 (  0.318393)
lacostenycoder
fonte