ความแตกต่างระหว่าง sys.stdout.write และการพิมพ์?


376

มีสถานการณ์ที่sys.stdout.write()ดีกว่าprintหรือไม่?

( ตัวอย่าง:ประสิทธิภาพที่ดีขึ้นรหัสที่สมเหตุสมผลมากขึ้น)


4
Python เวอร์ชันใด 2.x หรือ 3.x
Mark Byers

สุจริตฉันต้องการทราบทั้งสองอย่างแม้ว่าฉันจะไม่มีประสบการณ์กับ Python 3 อัปเดตคำถาม
Johanna Larsson

17
@ S.Lott: การถามถึงความแตกต่างพื้นฐานระหว่างsys.stdout.write()และprint(และ / หรือทำไม Python มีทั้งคู่) เป็นคำถามที่สมเหตุสมผลอย่างสมบูรณ์และไม่ต้องการตัวอย่าง OP ไม่ได้บอกว่าไวยากรณ์คำสั่งสับสน
smci

คำตอบ:


294

printเป็นเพียง wrapper บางที่จัดรูปแบบอินพุต (แก้ไขได้ แต่ตามค่าเริ่มต้นด้วยช่องว่างระหว่าง args และ newline ณ สิ้น) และเรียกใช้ฟังก์ชันการเขียนของวัตถุที่กำหนด โดยค่าเริ่มต้นวัตถุนี้คือsys.stdoutแต่คุณสามารถส่งไฟล์โดยใช้แบบฟอร์ม "บั้ง" ตัวอย่างเช่น:

print >> open('file.txt', 'w'), 'Hello', 'World', 2+3

ดู: https://docs.python.org/2/reference/simple_stmts.html?highlight=print#the-print-statement


ใน Python 3.x printกลายเป็นฟังก์ชั่น แต่ก็ยังเป็นไปได้ที่จะส่งผ่านสิ่งอื่นนอกเหนือsys.stdoutจากการfileโต้แย้ง

print('Hello', 'World', 2+3, file=open('file.txt', 'w'))

ดูhttps://docs.python.org/3/library/functions.html#print


ใน Python 2.6+ printยังคงเป็นคำสั่ง แต่สามารถใช้เป็นฟังก์ชันได้

from __future__ import print_function

ปรับปรุง: Bakuriu แสดงความคิดเห็นเพื่อชี้ให้เห็นว่ามีความแตกต่างเล็กน้อยระหว่างฟังก์ชั่นการพิมพ์และคำสั่งการพิมพ์ (และโดยทั่วไประหว่างฟังก์ชั่นและคำสั่ง)

ในกรณีที่มีข้อผิดพลาดเมื่อประเมินข้อโต้แย้ง:

print "something", 1/0, "other" #prints only something because 1/0 raise an Exception

print("something", 1/0, "other") #doesn't print anything. The function is not called

64
นอกจากนี้ยังเป็นที่น่าสังเกตว่ายังผนวกขึ้นบรรทัดใหม่เพื่อสิ่งที่คุณเขียนซึ่งไม่ได้เกิดขึ้นกับprint sys.stdout.write
Michael Mior

5
นอกจากนี้ยังsys.stdout.writeเป็นสากลมากขึ้นถ้าคุณจำเป็นต้องเขียนโค้ดแบบ dual-รุ่น (เช่นรหัสที่ทำงานพร้อมกันกับงูหลาม 2.x เช่นเดียวกับงูหลาม 3.x)
andreb

3
@MichaelMior คุณสามารถระงับการขึ้นบรรทัดใหม่ที่printผนวกด้วยเครื่องหมายจุลภาคต่อท้าย:print "this",; print "on the same line as this"
drevicko

1
@ bjd2385 >>ไม่ใช่ตัวดำเนินการ rshift ที่นี่ แต่เป็นรูปแบบ "บั้ง" เฉพาะของprintคำสั่ง ดูdocs.python.org/2/reference/...
luc

5
sys.stdout.write()ยังบัฟเฟอร์อินพุตและอาจไม่ล้างอินพุตไปยัง fd ทันที ในการสั่งซื้อเพื่อให้แน่ใจว่ามันจะทำงานเช่นฟังก์ชั่นการพิมพ์คุณควรเพิ่ม: sys.stdout.flush()
kerbelp

151

printก่อนจะแปลงวัตถุเป็นสตริง (ถ้ายังไม่ได้เป็นสตริง) มันจะใส่ช่องว่างหน้าวัตถุถ้าไม่ใช่จุดเริ่มต้นของบรรทัดและอักขระขึ้นบรรทัดใหม่ในตอนท้าย

เมื่อใช้stdoutงานคุณจะต้องแปลงวัตถุเป็นสตริงด้วยตัวคุณเอง (เช่นการเรียก "str" ​​เป็นต้น) และไม่มีอักขระขึ้นบรรทัดใหม่

ดังนั้น

print 99

เทียบเท่ากับ:

import sys
sys.stdout.write(str(99) + '\n')

32
+1 สำหรับการกล่าวถึงอักขระขึ้นบรรทัดใหม่! นี่คือความแตกต่างที่สำคัญระหว่างprintและ.write()ฉันจะบอกว่า
Eric O Lebigot

9
หมายเหตุ: printสามารถตัดบรรทัดใหม่ได้ ใน Python 2.x ให้ใส่เครื่องหมายจุลภาคท้ายและอักขระช่องว่างจะถูกส่งออก แต่ไม่มีการขึ้นบรรทัดใหม่ เช่นprint 99,ใน Python 3 print(..., end='')จะหลีกเลี่ยงการเพิ่มบรรทัดใหม่ (และยังหลีกเลี่ยงการเพิ่มพื้นที่เว้นเสียแต่ว่าคุณจะทำเช่นend=' 'นั้น
ToolmakerSteve

40
@EOL มันตลกขนาดไหนที่มีคนที่ชื่อ EOL แสดงความคิดเห็นเกี่ยวกับ '\ n' ... มันทำให้ฉันหัวเราะ ฉันไม่มีชีวิต ฆ่าฉัน.
Depado

2
ไม่เป็นความจริงprintการทำงานมีความแตกต่างกันเล็กน้อยในตัวจัดการสัญญาณใน python2.X เช่นการพิมพ์ไม่สามารถแทนที่ด้วย sys.stdout ในตัวอย่าง: stackoverflow.com/questions/10777610/ …
ddzialak

41

คำถามของฉันคือว่ามีสถานการณ์ที่sys.stdout.write()ดีกว่า หรือไม่ print

หลังจากเสร็จสิ้นการพัฒนาสคริปต์ในวันอื่น ๆ ฉันอัพโหลดไปยังเซิร์ฟเวอร์ unix ข้อความดีบั๊กทั้งหมดของฉันใช้ข้อความprintสั่งและข้อความเหล่านี้ไม่ปรากฏในบันทึกของเซิร์ฟเวอร์

นี่เป็นกรณีที่คุณอาจต้องการsys.stdout.writeแทน


8
ฮะ? คุณแน่ใจหรือว่านี่เป็นข้อแตกต่างระหว่างprint()และsys.stdout.write()ตรงข้ามกับความแตกต่างระหว่างstdoutและstderr? สำหรับการแก้จุดบกพร่องคุณควรใช้โมดูลที่พิมพ์ข้อความไปยังlogging stderr
ostrokach

1
ยา เช่นเดียวกันกับการใช้nohupและการเปลี่ยนเส้นทางไปยัง.outไฟล์
conner.xyz

1
การใช้ sys.stdout.flush () จะช่วยได้
suprit chaudhary

ถ้าคุณใช้nohupตามค่าเริ่มต้นการเขียนทั้งหมดไปstdoutและstderrจะเป็นอีกครั้งนำไปnohup.outโดยไม่คำนึงถึงว่าคุณจะใช้หรือprint stdout.write
เจิ้งเหอหลิว

40

นี่คือตัวอย่างโค้ดบางส่วนจากหนังสือLearning Pythonโดย Mark Lutz ที่ตอบคำถามของคุณ:

import sys
temp = sys.stdout                 # store original stdout object for later
sys.stdout = open('log.txt', 'w') # redirect all prints to this log file
print("testing123")               # nothing appears at interactive prompt
print("another line")             # again nothing appears. it's written to log file instead
sys.stdout.close()                # ordinary file object
sys.stdout = temp                 # restore print commands to interactive prompt
print("back to normal")           # this shows up in the interactive prompt

การเปิด log.txt ในเท็กซ์เอดิเตอร์จะเปิดเผยสิ่งต่อไปนี้:

testing123
another line

มีวิธีใดบ้างที่ฉันสามารถพิมพ์ไปที่หน้าจอรวมทั้งเขียนไฟล์ได้
Devesh Saini

5
@DeveshSaini: ใช่เพียงเขียนทับ sys.stdout ด้วยคลาสพร็อกซีที่มีฟังก์ชั่น write () และ flush () เป็นอย่างน้อย ผมเขียนตัวอย่าง snippet ที่นี่
ponycat

14

มีอย่างน้อยหนึ่งสถานการณ์ที่คุณต้องการsys.stdoutแทนที่จะพิมพ์

เมื่อคุณต้องการเขียนทับบรรทัดโดยไม่ต้องไปที่บรรทัดถัดไปเช่นขณะที่กำลังวาดแถบความคืบหน้าหรือข้อความสถานะคุณต้องวนซ้ำสิ่งที่ต้องการ

Note carriage return-> "\rMy Status Message: %s" % progress

sys.stdoutและเนื่องจากการพิมพ์เพิ่มขึ้นบรรทัดใหม่คุณจะดีกว่าการใช้


2
หากการพิมพ์เพิ่มบรรทัดใหม่ทำไมไม่พิมพ์ ('ข้อความ', end = '') แทน?
Apoorv Patne

8

คำถามของฉันคือว่ามีสถานการณ์ที่sys.stdout.write()ดีกว่าหรือไม่print

หากคุณกำลังเขียนแอปพลิเคชันบรรทัดคำสั่งที่สามารถเขียนไปยังไฟล์และ stdout ได้มันก็มีประโยชน์ คุณสามารถทำสิ่งต่าง ๆ เช่น:

def myfunc(outfile=None):
    if outfile is None:
        out = sys.stdout
    else:
        out = open(outfile, 'w')
    try:
        # do some stuff
        out.write(mytext + '\n')
        # ...
    finally:
        if outfile is not None:
            out.close()

หมายความว่าคุณไม่สามารถใช้with open(outfile, 'w') as out:รูปแบบได้ แต่บางครั้งก็คุ้มค่า


พูดอย่างเคร่งครัดคุณสามารถใช้with- def process(output): # .../ if outfile is None: process(sys.stdout) else: with open(outfile, 'w') as out: process(out)(เพิ่มบรรทัดใหม่หากจำเป็น) แน่นอนว่ามันไม่สะอาดมาก แต่แน่นอน
คดีฟ้องร้องกองทุนโมนิก้า

4

ใน 2.x printคำสั่งประมวลผลก่อนสิ่งที่คุณให้มันเปลี่ยนเป็นสตริงไปพร้อมกันจัดการตัวคั่นและขึ้นบรรทัดใหม่และช่วยให้การเปลี่ยนเส้นทางไปยังไฟล์ 3.x เปลี่ยนเป็นฟังก์ชั่น แต่ก็ยังมีความรับผิดชอบเหมือนเดิม

sys.stdout เป็นไฟล์หรือไฟล์ที่มีวิธีการเขียนซึ่งใช้สตริงหรือบางสิ่งบางอย่างตามสายนั้น


3

มันจะดีกว่าเมื่อการพิมพ์แบบไดนามิกมีประโยชน์ตัวอย่างเช่นเพื่อให้ข้อมูลในกระบวนการที่ยาวนาน:

import time, sys
Iterations = 555
for k in range(Iterations+1):
    # some code to execute here ...
    percentage = k / Iterations
    time_msg = "\rRunning Progress at {0:.2%} ".format(percentage)
    sys.stdout.write(time_msg)
    sys.stdout.flush()
    time.sleep(0.01)

2
พิมพ์ (time_msg, end = '') แทน sys.stdout.write (time_msg) sys.stdout.flush () สามารถใช้งานได้
rluts

2
>>> sys.stdout.write(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: expected a string or other character buffer object
>>> sys.stdout.write("a")
a>>> sys.stdout.write("a") ; print(1)
a1

สังเกตตัวอย่างข้างต้น:

  1. sys.stdout.writeจะไม่เขียนวัตถุที่ไม่ใช่สตริง แต่printจะ

  2. sys.stdout.writeจะไม่เพิ่มสัญลักษณ์บรรทัดใหม่ในท้ายที่สุด แต่printจะ

ถ้าเราดำน้ำลึก

sys.stdout เป็นวัตถุไฟล์ที่สามารถใช้สำหรับการส่งออกของการพิมพ์ ()

หากprint()ไม่ได้ระบุอาร์กิวเมนต์ไฟล์ไว้sys.stdoutจะถูกใช้


1

มีสถานการณ์ที่ควรพิมพ์ sys.stdout.write () หรือไม่?

ตัวอย่างเช่นฉันกำลังทำงานกับฟังก์ชั่นขนาดเล็กซึ่งพิมพ์ดาวในรูปแบบพีระมิดเมื่อผ่านตัวเลขเป็นอาร์กิวเมนต์ถึงแม้ว่าคุณสามารถทำได้โดยใช้end = ""เพื่อพิมพ์ในบรรทัดแยกกันฉันใช้sys.stdout.writeในการประสานงาน ด้วยการพิมพ์เพื่อให้งานนี้ หากต้องการอธิบายอย่างละเอียดเกี่ยวกับstdout.writeนี้จะพิมพ์ในบรรทัดเดียวกันโดยที่การพิมพ์จะพิมพ์เนื้อหาในบรรทัดแยกต่างหากเสมอ

import sys

def printstars(count):

    if count >= 1:
        i = 1
        while (i <= count):
            x=0
            while(x<i):
                sys.stdout.write('*')
                x = x+1
            print('')
            i=i+1

printstars(5)

1

มีสถานการณ์ที่ควรพิมพ์ sys.stdout.write () หรือไม่?

ฉันพบว่า stdout ทำงานได้ดีกว่าการพิมพ์ในสถานการณ์แบบมัลติเธรด ฉันใช้ Queue (FIFO) เพื่อจัดเก็บบรรทัดที่จะพิมพ์และฉันเก็บเธรดทั้งหมดไว้ก่อนหน้าบรรทัดการพิมพ์จนกว่างานพิมพ์ Q ของฉันจะว่างเปล่า ถึงกระนั้นการใช้งานพิมพ์ฉันอาจสูญเสีย \ n ขั้นสุดท้ายในการดีบัก I / O (ใช้ wing pro IDE)

เมื่อฉันใช้ std.out กับ \ n ในสตริงรูปแบบการดีบัก I / O อย่างถูกต้องและ \ n นั้นจะแสดงอย่างถูกต้อง


คุณรู้เหตุผลว่าทำไม stdout ควรทำงานได้ดีกว่าการพิมพ์ในกรณีนี้หรือเป็นข้อมูลนี้หรือไม่? คุณสามารถให้ตัวอย่างการทำงานน้อยที่สุดเมื่อเกิดเหตุการณ์นี้ขึ้นได้ไหม
2653663

ความคิดของฉันคือ stdout ทำงานในระดับต่ำกว่าการพิมพ์ แน่นอนฉันมีความเสียหายของเธรดเนื่องจากงานพิมพ์สองชุดกำลังต่อสู้เพื่อป้อนผ่าน stdout เขียนถึง stdout หนึ่งจากแต่ละหัวข้อลบความเสียหายสำหรับฉัน
David Poundall


1

ใน Python 3 มีเหตุผลที่ถูกต้องที่จะใช้การพิมพ์ผ่านsys.stdout.writeแต่เหตุผลนี้สามารถเปลี่ยนเป็นเหตุผลที่จะใช้sys.stdout.writeแทน

ด้วยเหตุนี้เองขณะนี้การพิมพ์คือฟังก์ชันใน Python 3 คุณสามารถแทนที่สิ่งนี้ได้ ดังนั้นคุณสามารถใช้การพิมพ์ได้ทุกที่ในสคริปต์อย่างง่ายและตัดสินใจว่าต้องพิมพ์คำสั่งเหล่านั้นstderrแทน ตอนนี้คุณสามารถกำหนดฟังก์ชั่นการพิมพ์ใหม่ได้คุณสามารถเปลี่ยนฟังก์ชั่นการพิมพ์ได้ด้วยการเปลี่ยนโดยใช้โมดูล builtins นอกหลักสูตรด้วยfile.writeคุณสามารถระบุไฟล์ได้ แต่ด้วยการพิมพ์ทับคุณสามารถกำหนดตัวคั่นบรรทัดใหม่หรือตัวแยกอาร์กิวเมนต์

อีกวิธีคือ บางทีคุณอาจจะแน่ใจว่าคุณเขียนถึงstdoutแต่ยังรู้ว่าคุณจะเปลี่ยนการพิมพ์เป็นอย่างอื่นคุณสามารถตัดสินใจที่จะใช้sys.stdout.writeและใช้พิมพ์สำหรับบันทึกข้อผิดพลาดหรืออย่างอื่น

ดังนั้นสิ่งที่คุณใช้ขึ้นอยู่กับว่าคุณตั้งใจจะใช้มันอย่างไร printมีความยืดหยุ่นมากขึ้น แต่นั่นอาจเป็นเหตุผลที่จะใช้และไม่ใช้ ฉันยังคงต้องการความยืดหยุ่นแทนและเลือกพิมพ์ อีกเหตุผลที่ใช้printแทนก็คือความคุ้นเคย คนอื่น ๆ sys.stdout.writeจะตอนนี้สิ่งที่คุณหมายถึงโดยการพิมพ์และการรู้น้อย


1

หนึ่งในความแตกต่างคือสิ่งต่อไปนี้เมื่อพยายามพิมพ์ไบต์ในลักษณะเลขฐานสิบหก ตัวอย่างเช่นเรารู้ว่าค่าทศนิยมของ255อยู่0xFFในลักษณะเลขฐานสิบหก:

val = '{:02x}'.format(255) 

sys.stdout.write(val) # prints ff2
print(val)            # prints ff

นั่นไม่ใช่สิ่งที่เป็นเรื่องเกี่ยวกับ มันจะเกิดขึ้นในเชลล์แบบโต้ตอบเท่านั้นและเนื่องจาก ... write()ไม่ได้เพิ่ม\nและส่งกลับ (และแสดงเชลล์แบบโต้ตอบ) ค่าส่งคืนของฟังก์ชัน (จำนวนอักขระที่เขียน) การแสดงเลขฐานสิบหกหรือเนื้อหาอื่น ๆ ที่แสดงเป็นสาระสำคัญ
Ondrej K.

0

ใน python 2 ถ้าคุณต้องการส่งผ่านฟังก์ชันคุณสามารถกำหนด os.sys.stdout.write ให้กับตัวแปรคุณไม่สามารถทำสิ่งนี้ (ในสำเนา) ด้วยการพิมพ์

>import os
>>> cmd=os.sys.stdout.write
>>> cmd('hello')
hello>>> 

ทำงานได้ตามที่คาดไว้

>>> cmd=print
  File "<stdin>", line 1
    cmd=print
            ^
SyntaxError: invalid syntax

ที่ใช้งานไม่ได้ พิมพ์เป็นฟังก์ชั่นที่มีมนต์ขลัง


0

ความแตกต่างระหว่างprintและsys.stdout.writeจุดใน Python 3 ก็เป็นค่าที่ถูกส่งคืนเมื่อดำเนินการในเทอร์มินัล ใน Python 3 sys.stdout.writeส่งคืนความยาวของสตริงในขณะที่printส่งคืนเพียงNoneผลตอบแทนเพียง

ตัวอย่างเช่นการรันโค้ดต่อไปนี้แบบโต้ตอบใน terminal จะพิมพ์สตริงตามด้วยความยาวของมันเนื่องจาก lenght จะถูกส่งกลับและส่งออกเมื่อทำงานแบบโต้ตอบ:

>>> sys.stdout.write(" hi ")
 hi 4
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.