p vs wkłada Ruby

270

Czy jest jakaś różnica między Ruby pi pomiędzy nimi puts?

Collimarco
źródło

Odpowiedzi:

334

p foowypisuje foo.inspectznak nowej linii, tzn. wypisuje wartość inspectzamiast zamiast to_s, co jest bardziej odpowiednie do debugowania (ponieważ można np. odróżnić 1, "1"a od "2\b1"czego nie można drukować bez inspect).

sepp2k
źródło
7
Tak, p (i puts) są w module jądra, więc możesz zobaczyć szczegóły tutaj: ruby-doc.org/core/classes/Kernel.html#M005961
mikej
17
Zauważ, że pzwraca również wartość obiektu, podczas gdy putsnie. 1.9.3p125 :002 > (p "foo").class "foo" => String 1.9.3p125 :003 > (puts "foo").class foo => NilClass
Darren Cheng
2
Świetne podsumowanie dostarczone przez Garetha Reesa w jego poście zatytułowanym „Ruby p vs puts vs print” .
alexanderjsingleton
Czuję się tak, jakby to pozostawiło mi króliczą dziurę pytań. Co sprawdzasz? Co to jest? Dlaczego chcę sprawdzać wydrukowany tekst zamiast zmiennej? Który jest bardziej standardowy w świecie programowania, ponieważ wspomniałeś o debugowaniu, p lub putach? Czy po zakończeniu debugowania wszystkie „p” należy zastąpić słowami „put”? Widzę w powyższym komentarzu, że p zwraca obiekt, co jest ogromną różnicą. Nie jestem pewien, czy ta odpowiedź jest kompletna, jeśli tylko wspomina o niewielkiej różnicy, która doprowadzi do większych pytań, które nadal stanowią odpowiedź na pierwotne pytanie.
1
@AaronLoften to_sjest standardową metodą ciągów w języku Ruby. inspect. jak powiedziałem, jest alternatywą dla metody string, która daje wyjście bardziej odpowiednie do debugowania. Po zakończeniu debugowania powinieneś oczywiście usunąć instrukcje debugowania (lub w przypadku poważniejszych projektów prawdopodobnie powinieneś użyć struktury rejestrowania i nie używać p lub putów do debugowania w ogóle). Fakt, że obiekt jest pzwracany, wydaje się nieistotny w większości sytuacji (i sądzę, że udzieliłem tej odpowiedzi, zanim tak się stało). Różnica w wydajności jest główną różnicą (i kiedyś była jedyną).
sepp2k
54

Należy również zauważyć, że puts„reaguje” na to_szdefiniowaną klasę , pa nie. Na przykład:

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>

Wynika to bezpośrednio z .inspectpołączenia, ale w praktyce nie jest to oczywiste.

ezpz
źródło
37

p foo jest taki sam jak puts foo.inspect

August Lilleaas
źródło
4
ale putszwraca nil, zamiast foojak robi p.
ribamar
10
To jest źle. To to samo, coputs foo.inspect; foo
Eric Duminil
Dowodzi to, że jesteś odpowiedź jest niepoprawna: (-> {p "Hello World"}.call) == (-> {puts "Hello World".inspect}.call ) . Wiele głosów pozytywnych NIE czyni z tego dobrej odpowiedzi!
lacostenycoder
3

Oprócz powyższych odpowiedzi istnieje subtelna różnica w wynikach konsolowych - mianowicie obecność / brak odwróconych przecinków / cudzysłowów - które mogą być przydatne:

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

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

Uważam to za przydatne, jeśli chcesz zrobić prosty pasek postępu, używając ich bliskiego krewnego, wydrukuj :

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

Daje to pasek postępu 100%:

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

A to dodaje przyrostowe * przy każdej iteracji:

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
źródło
2

Z dokumentu ruby-2.4.1

stawia

puts(obj, ...) → nil

Zapisuje podane obiekty w systemie iOS. Zapisuje nowy wiersz po dowolnym, który jeszcze nie kończy się sekwencją nowego wiersza. Zwraca zero .

Strumień musi być otwarty do zapisu. Wywołany z argumentem tablicowym zapisuje każdy element w nowym wierszu. Każdy dany obiekt, który nie jest łańcuchem ani tablicą, zostanie przekonwertowany przez wywołanie jego to_s metody. Wywołany bez argumentów, wyświetla pojedynczy znak nowej linii.

spróbujmy na 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
Dla każdego obiektu zapisuje bezpośrednio, obj.inspecta następnie nowy wiersz na standardowe wyjście programu.

w 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
źródło
0

Te 2 są równe:

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

( inspekcja daje bardziej dosłowny widok obiektu w porównaniu do metody to_s )

apadana
źródło
wydają się równi, ale NIE są. Spróbuj:(->{p "Hello World"}.call) == (-> {puts "Hello World".inspect}.call )
lacostenycoder
0

Może to ilustrować jedną z kluczowych różnic, która polega na tym, że pzwraca wartość tego, co jest do niej przekazywane, gdzie putszwraca 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']

Testy porównawcze putssą wolniejsze

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
źródło