Ich versuche, einige der Code-Golf- Herausforderungen zu meistern, aber für alle muss der Input entnommen werden stdin
. Wie bekomme ich das in Python?
Ich versuche, einige der Code-Golf- Herausforderungen zu meistern, aber für alle muss der Input entnommen werden stdin
. Wie bekomme ich das in Python?
Antworten:
Sie könnten das fileinput
Modul verwenden:
import fileinput
for line in fileinput.input():
pass
fileinput
Durchläuft alle Zeilen in der Eingabe, die als Dateinamen in Befehlszeilenargumenten angegeben sind, oder die Standardeingabe, wenn keine Argumente angegeben sind.
Hinweis: line
Enthält einen nachgestellten Zeilenumbruch. um es zu entfernen verwendenline.rstrip()
Es gibt einige Möglichkeiten, dies zu tun.
sys.stdin
ist ein dateiähnliches Objekt, für das Sie Funktionen aufrufen können read
oder readlines
wenn Sie alles lesen oder alles lesen und automatisch durch Zeilenumbruch teilen möchten. (Sie müssen, import sys
damit dies funktioniert.)
Wenn Sie möchten , aufgefordert , den Benutzer zur Eingabe, können Sie raw_input
in Python 2.x, und nur input
in Python 3.
Wenn Sie eigentlich nur Befehlszeilenoptionen lesen möchten, können Sie über die Liste sys.argv darauf zugreifen .
Sie werden diesen Wikibook-Artikel über E / A in Python wahrscheinlich auch als nützliche Referenz finden.
import sys
for line in sys.stdin:
print(line)
Beachten Sie, dass dies am Ende ein Zeilenumbruchzeichen enthält. Um die neue Zeile am Ende zu entfernen, verwenden Sie line.rstrip()
wie @brittohalloran sagte.
\r\n
Zeilenenden umgehen
Python hat auch eingebaute Funktionen input()
und raw_input()
. Weitere Informationen finden Sie in der Python-Dokumentation unter Integrierte Funktionen .
Zum Beispiel,
name = raw_input("Enter your name: ") # Python 2.x
oder
name = input("Enter your name: ") # Python 3
Hier ist aus Python lernen :
import sys
data = sys.stdin.readlines()
print "Counted", len(data), "lines."
Unter Unix können Sie es testen, indem Sie Folgendes tun:
% cat countlines.py | python countlines.py
Counted 3 lines.
Unter Windows oder DOS würden Sie Folgendes tun:
C:\> type countlines.py | python countlines.py
Counted 3 lines.
print(sum(chunk.count('\n') for chunk in iter(partial(sys.stdin.read, 1 << 15), '')))
. siehewc-l.py
cat
hier ist überflüssig. Der korrekte Aufruf für Unix-Systeme lautet python countlines.py < countlines.py
.
readlines()
. Dateiobjekte sollen wiederholt werden, ohne dass alle Daten im Speicher materialisiert werden.
Wie liest du von stdin in Python?
Ich versuche, einige der Code-Golf-Herausforderungen zu meistern, aber für alle muss der Input von stdin übernommen werden. Wie bekomme ich das in Python?
Sie können verwenden:
sys.stdin
- Ein dateiähnliches Objekt - Aufruf sys.stdin.read()
, um alles zu lesen.input(prompt)
- Übergeben Sie eine optionale Eingabeaufforderung, sie liest von stdin bis zur ersten neuen Zeile, die sie entfernt. Sie müssten dies wiederholt tun, um mehr Zeilen zu erhalten. Am Ende der Eingabe wird EOFError ausgelöst. (Wahrscheinlich nicht gut zum Golfen.) In Python 2 ist dies rawinput(prompt)
.open(0).read()
- In Python 3 open
akzeptiert die integrierte Funktion Dateideskriptoren (Ganzzahlen , die die E / A- Ressourcen des Betriebssystems darstellen), und 0 ist der Deskriptor von stdin
. Es gibt ein dateiähnliches Objekt zurück sys.stdin
- wahrscheinlich die beste Wahl zum Golfen. In Python 2 ist dies io.open
.open('/dev/stdin').read()
- open(0)
funktioniert ähnlich unter Python 2 und 3, jedoch nicht unter Windows (oder sogar Cygwin).fileinput.input()
- gibt einen Iterator über Zeilen in allen in aufgelisteten Dateien zurück sys.argv[1:]
oder stdin, falls nicht angegeben. Verwenden Sie wie ''.join(fileinput.input())
.Beide sys
und fileinput
müssen natürlich jeweils importiert werden.
sys.stdin
Beispiele, die mit Python 2 und 3, Windows und Unix kompatibel sindSie müssen nur read
aus sys.stdin
, zum Beispiel, wenn Sie Rohrdaten stdin:
$ echo foo | python -c "import sys; print(sys.stdin.read())"
foo
Wir können sehen, dass sys.stdin
sich dies im Standardtextmodus befindet:
>>> import sys
>>> sys.stdin
<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>
Angenommen, Sie haben eine Datei. inputs.txt
Wir können diese Datei akzeptieren und wieder ausschreiben:
python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
Hier ist eine vollständige, leicht replizierbare Demo mit zwei Methoden, der integrierten Funktion input
(Verwendung raw_input
in Python 2) und sys.stdin
. Die Daten sind unverändert, sodass die Verarbeitung nicht ausgeführt wird.
Lassen Sie uns zunächst eine Datei für Eingaben erstellen:
$ python -c "print('foo\nbar\nbaz')" > inputs.txt
Mit dem Code, den wir bereits gesehen haben, können wir überprüfen, ob wir die Datei erstellt haben:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Hier ist die Hilfe sys.stdin.read
von Python 3:
read(size=-1, /) method of _io.TextIOWrapper instance
Read at most n characters from stream.
Read from underlying buffer until we have n characters or we hit EOF.
If n is negative or omitted, read until EOF.
input
( raw_input
in Python 2)Die eingebaute Funktion input
liest von der Standardeingabe bis zu einer neuen Zeile, die entfernt wird (ergänzend print
, wodurch standardmäßig eine neue Zeile hinzugefügt wird). Dies geschieht, bis EOF (End Of File) abgerufen wird und an diesem Punkt ausgelöst wird EOFError
.
So können Sie input
in Python 3 (oder raw_input
in Python 2) aus stdin lesen - also erstellen wir ein Python-Modul, das wir stdindemo.py nennen:
$ python -c "print('try:\n while True:\n print(input())\nexcept EOFError:\n pass')" > stdindemo.py
Und drucken wir es wieder aus, um sicherzustellen, dass es so ist, wie wir es erwarten:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo.py
try:
while True:
print(input())
except EOFError:
pass
Auch hier input
liest , bis die Newline und im Wesentlichen Streifen es von der Linie.print
fügt eine neue Zeile hinzu. Während beide die Eingabe ändern, werden ihre Änderungen abgebrochen. (Sie ergänzen sich also im Wesentlichen gegenseitig.)
Und wenn input
das Zeichen für das Dateiende angezeigt wird, wird EOFError ausgelöst, das wir ignorieren und dann aus dem Programm beenden.
Und unter Linux / Unix können wir von cat leiten:
$ cat inputs.txt | python -m stdindemo
foo
bar
baz
Oder wir können die Datei einfach von stdin umleiten:
$ python -m stdindemo < inputs.txt
foo
bar
baz
Wir können das Modul auch als Skript ausführen:
$ python stdindemo.py < inputs.txt
foo
bar
baz
Hier ist die Hilfe zum eingebauten input
Python 3:
input(prompt=None, /)
Read a string from standard input. The trailing newline is stripped.
The prompt string, if given, is printed to standard output without a
trailing newline before reading input.
If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
On *nix systems, readline is used if available.
sys.stdin
Hier machen wir ein Demo-Skript mit sys.stdin
. Der effiziente Weg, um über ein dateiähnliches Objekt zu iterieren, besteht darin, das dateiähnliche Objekt als Iterator zu verwenden. Die ergänzende Methode zum Schreiben von dieser Eingabe in stdout besteht darin, einfach Folgendes zu verwenden sys.stdout.write
:
$ python -c "print('import sys\nfor line in sys.stdin:\n sys.stdout.write(line)')" > stdindemo2.py
Drucken Sie es wieder aus, um sicherzustellen, dass es richtig aussieht:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo2.py
import sys
for line in sys.stdin:
sys.stdout.write(line)
Und die Eingaben in die Datei umleiten:
$ python -m stdindemo2 < inputs.txt
foo
bar
baz
Golf in einen Befehl:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Da die Dateideskriptoren für stdin
und stdout
0 bzw. 1 sind, können wir diese auch open
in Python 3 übergeben (nicht 2, und beachten Sie, dass wir zum Schreiben in stdout immer noch das 'w' benötigen).
Wenn dies auf Ihrem System funktioniert, werden mehr Zeichen entfernt.
$ python -c "open(1,'w').write(open(0).read())" < inputs.txt
baz
bar
foo
Python 2 io.open
macht das auch, aber der Import nimmt viel mehr Platz in Anspruch:
$ python -c "from io import open; open(1,'w').write(open(0).read())" < inputs.txt
foo
bar
baz
Ein Kommentar schlägt ''.join(sys.stdin)
für das Golfen vor, aber das ist tatsächlich länger als sys.stdin.read () - plus Python muss eine zusätzliche Liste im Speicher erstellen (so str.join
funktioniert es, wenn keine Liste angegeben wird) - für den Kontrast:
''.join(sys.stdin)
sys.stdin.read()
Die beste Antwort lautet:
import fileinput
for line in fileinput.input():
pass
Da sys.stdin
jedoch die Datei-API einschließlich des Iterator-Protokolls implementiert wird, ist dies genau das Gleiche wie folgt:
import sys
for line in sys.stdin:
pass
Eine andere Antwort legt dies nahe. Denken Sie daran , dass , wenn Sie es in einem Dolmetscher zu tun, werden Sie tun müssen Ctrl- dwenn Sie unter Linux oder Mac, oder Ctrl- zunter Windows (nach Enter) , um die End-of-Datei Zeichen an den Prozess zu senden. Diese Antwort schlägt außerdem vor, stattdessen print(line)
eine '\n'
Verwendung zu print(line, end='')
verwenden (falls in Python 2 erforderlich from __future__ import print_function
).
Der eigentliche Anwendungsfall für fileinput
ist das Einlesen einer Reihe von Dateien.
Die von anderen vorgeschlagene Antwort:
for line in sys.stdin:
print line
ist sehr einfach und pythonisch, aber es muss beachtet werden, dass das Skript bis EOF wartet, bevor es mit der Iteration in den Eingabezeilen beginnt.
Dies bedeutet, dass tail -f error_log | myscript.py
Zeilen nicht wie erwartet verarbeitet werden.
Das richtige Skript für einen solchen Anwendungsfall wäre:
while 1:
try:
line = sys.stdin.readline()
except KeyboardInterrupt:
break
if not line:
break
print line
UPDATE
Aus den Kommentaren geht hervor, dass unter Python 2 möglicherweise nur Pufferung erforderlich ist, sodass Sie am Ende darauf warten müssen, dass der Puffer oder EOF gefüllt wird, bevor der Druckaufruf ausgegeben wird.
for line in sys.stdin:
Muster wartet nicht auf EOF. Wenn Sie jedoch sehr kleine Dateien testen, werden die Antworten möglicherweise gepuffert. Testen Sie mit mehr Daten, um festzustellen, ob Zwischenergebnisse gelesen werden.
print line
ist in 3.1.3 nicht aufgewacht, print(line)
tut es aber .
for line in sys.stdin:
blockiert nicht bis EOF. In Python 2 gibt es einen Read-Ahead-Fehler , der die Zeilen verzögert, bis der entsprechende Puffer voll ist. Es handelt sich um ein Pufferproblem, das nicht mit EOF zusammenhängt. for line in iter(sys.stdin.readline, ''):
Verwenden Sie io.open()
zur Umgehung dieses Problems ( für normale Dateien verwenden). Sie brauchen es nicht in Python 3.
Aufbauend auf allen Antworten sys.stdin
, die Sie verwenden , können Sie auch Folgendes tun, um aus einer Argumentdatei zu lesen, wenn mindestens ein Argument vorhanden ist, und ansonsten auf stdin zurückgreifen:
import sys
f = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
for line in f:
# Do your stuff
und benutze es entweder
$ python do-my-stuff.py infile.txt
oder
$ cat infile.txt | python do-my-stuff.py
oder auch
$ python do-my-stuff.py < infile.txt
Das wäre Ihr Python - Skript verhalten sich wie viele GNU / Unix - Programme machen wie cat
, grep
und sed
.
argparse
ist eine einfache LösungBeispiel, das mit beiden Python-Versionen 2 und 3 kompatibel ist:
#!/usr/bin/python
import argparse
import sys
parser = argparse.ArgumentParser()
parser.add_argument('infile',
default=sys.stdin,
type=argparse.FileType('r'),
nargs='?')
args = parser.parse_args()
data = args.infile.read()
Sie können dieses Skript auf verschiedene Arten ausführen:
1. Verwenden von stdin
echo 'foo bar' | ./above-script.py
oder kürzer durch Ersetzen echo
durch hier Zeichenfolge :
./above-script.py <<< 'foo bar'
2. Verwenden eines Dateinamenarguments
echo 'foo bar' > my-file.data
./above-script.py my-file.data
3. Verwenden Sie stdin
den speziellen Dateinamen-
echo 'foo bar' | ./above-script.py -
add_argument('--in'
und dann zum Skript weiterleiten und --in -
zur Befehlszeile hinzufügen . PS in
ist kein sehr guter Name für eine Variable / ein Attribut.
in
ist nicht nur ein schlechter Name für eine Variable, sondern auch illegal. args.in.read()
löst aufgrund des in
reservierten Schlüsselworts einen InvalidSyntax-Fehler aus . Kann einfach umbenannt werden, um infile
die Python Argparse-Dokumente zu mögen: docs.python.org/3/library/…
Der folgende Code-Chip hilft Ihnen dabei (er liest alle stdin-Blockierungen EOF
in einer Zeichenfolge):
import sys
input_str = sys.stdin.read()
print input_str.split()
Ich bin ziemlich erstaunt, dass bisher niemand diesen Hack erwähnt hat:
python -c "import sys; set(map(sys.stdout.write,sys.stdin))"
In Python2 können Sie den set()
Anruf abbrechen , aber es würde so oder so lauten
readlines
diese Aufteilung in Zeilen und dann join
wieder verwenden? Sie können einfach schreibenprint(sys.stdin.read())
write
kehrt zurück None
und die festgelegte Größe würde niemals größer als 1 ( =len(set([None]))
) sein
Sie können wie folgt aus stdin lesen und Eingaben in "Daten" speichern :
data = ""
for line in sys.stdin:
data += line
data = sys.stdin.read()
ohne das Problem wiederholter Verkettungen von Zeichenfolgen durchgeführt werden.
Lesen von sys.stdin
, aber um Binärdaten unter Windows zu lesen , müssen Sie besonders vorsichtig sein, da diese sys.stdin
im Textmodus geöffnet sind und das \r\n
Ersetzen durch sie beschädigt\n
.
Die Lösung besteht darin, den Modus auf binär zu setzen, wenn Windows + Python 2 erkannt wird, und unter Python 3 zu verwenden sys.stdin.buffer
.
import sys
PY3K = sys.version_info >= (3, 0)
if PY3K:
source = sys.stdin.buffer
else:
# Python 2 on Windows opens sys.stdin in text mode, and
# binary data that read from it becomes corrupted on \r\n
if sys.platform == "win32":
# set sys.stdin to binary mode
import os, msvcrt
msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
source = sys.stdin
b = source.read()
Ich benutze die folgende Methode, sie gibt einen String von stdin zurück (ich benutze ihn für das JSON-Parsing). Es funktioniert mit Pipe und Eingabeaufforderung unter Windows (noch nicht unter Linux getestet). Bei der Eingabeaufforderung zeigen zwei Zeilenumbrüche das Ende der Eingabe an.
def get_from_stdin():
lb = 0
stdin = ''
for line in sys.stdin:
if line == "\n":
lb += 1
if lb == 2:
break
else:
lb = 0
stdin += line
return stdin
Das Problem habe ich mit der Lösung
import sys
for line in sys.stdin:
print(line)
Wenn Sie keine Daten an stdin übergeben, werden diese für immer blockiert. Deshalb liebe ich diese Antwort : Überprüfen Sie zuerst, ob Daten zu stdin vorhanden sind, und lesen Sie sie dann. Das habe ich letztendlich getan:
import sys
import select
# select(files to read from, files to write to, magic, timeout)
# timeout=0.0 is essential b/c we want to know the asnwer right away
if select.select([sys.stdin], [], [], 0.0)[0]:
help_file_fragment = sys.stdin.read()
else:
print("No data passed to stdin", file=sys.stderr)
sys.exit(2)
select
Aufruf fast nie "bereit" ist. oder Sie könnten auch Probleme haben, wenn stdin mit einer Datei auf einem langsamen Medium (Netzwerk, CD, Band usw.) verbunden ist. Sie sagten: "Wenn Sie keine Daten an stdin übergeben, werden diese für immer blockiert." ist ein Problem , aber ich würde sagen, es ist eine Funktion . Die meisten CLI-Programme (z. B. cat
) funktionieren auf diese Weise, und dies wird erwartet. EOF ist das einzige, worauf Sie sich verlassen sollten, um das Ende der Eingabe zu erkennen.
Ich hatte einige Probleme, als dies zum Lesen über die daran angeschlossenen Steckdosen funktionierte. Als der Socket geschlossen wurde, gab er eine leere Zeichenfolge in einer aktiven Schleife zurück. Das ist also meine Lösung dafür (die ich nur unter Linux getestet habe, aber ich hoffe, dass sie auf allen anderen Systemen funktioniert).
import sys, os
sep=os.linesep
while sep == os.linesep:
data = sys.stdin.readline()
sep = data[-len(os.linesep):]
print '> "%s"' % data.strip()
Wenn Sie also anfangen, einen Socket zu hören, funktioniert er ordnungsgemäß (z. B. in Bash):
while :; do nc -l 12345 | python test.py ; done
Und Sie können es mit Telnet aufrufen oder einfach einen Browser auf localhost zeigen: 12345
Was das betrifft:
for line in sys.stdin:
Ich habe es gerade unter Python 2.7 (auf Vorschlag eines anderen) für eine sehr große Datei versucht, und ich empfehle es nicht, genau aus den oben genannten Gründen (lange passiert nichts).
Am Ende hatte ich eine etwas pythonischere Lösung (und sie funktioniert bei größeren Dateien):
with open(sys.argv[1], 'r') as f:
for line in f:
Dann kann ich das Skript lokal ausführen als:
python myscript.py "0 1 2 3 4..." # can be a multi-line string or filename - any std.in input will work
sys.stdin
das Skript als Befehlszeilenargument.
sys.stdin
als Befehlszeilenargument an das Skript übergeben? Argumente sind Zeichenfolgen und Streams sind dateiähnliche Objekte, sie sind nicht gleich.
sys.stdin
handelt es sich um ein dateiähnliches Objekt
Für Python 3 wäre das:
# Filename e.g. cat.py
import sys
for line in sys.stdin:
print(line, end="")
Dies ist im Grunde eine einfache Form von Katze (1), da nicht nach jeder Zeile eine neue Zeile hinzugefügt wird. Sie können dies verwenden (nachdem Sie die ausführbare Datei chmod +x cat.py
wie folgt markiert haben :
echo Hello | ./cat.py
Wenn Sie den -c
Befehl auf knifflige Weise verwenden, können Sie anstelle des stdin
(und in einigen Fällen flexibleren) Befehls auch einen Shell-Skriptbefehl an Ihren Python-Befehl übergeben, indem Sie den Befehl sell in Anführungszeichen in einer durch ein $
Zeichen gestellten Klammer setzen .
z.B
python3 -c "import sys; print(len(sys.argv[1].split('\n')))" "$(cat ~/.goldendict/history)"
Dies zählt die Anzahl der Zeilen aus der Verlaufsdatei von goldendict.