Я намагаюся виконати деякі проблеми з кодом для гольфу , але всі вони вимагають взяти дані stdin
. Як я можу це отримати в Python?
Я намагаюся виконати деякі проблеми з кодом для гольфу , але всі вони вимагають взяти дані stdin
. Як я можу це отримати в Python?
Відповіді:
Ви можете використовувати fileinput
модуль:
import fileinput
for line in fileinput.input():
pass
fileinput
пройде через всі рядки у введенні, вказані як імена файлів, наведені в аргументах командного рядка, або як стандартне введення, якщо аргументи не надано.
Примітка: line
міститиме зворотний новий рядок; щоб видалити його, використовуйтеline.rstrip()
Є кілька способів це зробити.
sys.stdin
є файлоподібним об'єктом, за яким можна викликати функції read
або readlines
якщо ви хочете прочитати все або ви хочете прочитати все і розділити його на новий рядок автоматично. (Вам потрібно import sys
для цього працювати.)
Якщо ви хочете запропонувати користувачеві ввести, ви можете використовувати raw_input
в Python 2.X і просто input
в Python 3.
Якщо ви дійсно хочете прочитати параметри командного рядка, ви можете отримати доступ до них через список sys.argv .
Напевно, ця стаття Wikibook про введення-виведення в Python також стане корисною довідкою.
import sys
for line in sys.stdin:
print(line)
Зауважте, що це буде містити символ нового рядка в кінці. Щоб видалити line.rstrip()
нову лінію в кінці, використовуйте як сказано @brittohalloran.
\r\n
закінчень рядків
Python також має вбудовані функції input()
та raw_input()
. Дивіться документацію Python у розділі Вбудовані функції .
Наприклад,
name = raw_input("Enter your name: ") # Python 2.x
або
name = input("Enter your name: ") # Python 3
Ось з Learning Python :
import sys
data = sys.stdin.readlines()
print "Counted", len(data), "lines."
У Unix ви можете перевірити це, зробивши щось на кшталт:
% cat countlines.py | python countlines.py
Counted 3 lines.
У Windows або DOS ви зробите:
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), '')))
. див.wc-l.py
cat
тут є зайвим. Правильне виклик для систем Unix є python countlines.py < countlines.py
.
readlines()
. Файлові об'єкти призначені для повторного повторення даних, не оформивши всі дані в пам'яті.
Як ви читаєте зі stdin в Python?
Я намагаюся виконати деякі проблеми з кодом для гольфу, але всі вони вимагають взяти вклад із stdin. Як я можу це отримати в Python?
Ви можете використовувати:
sys.stdin
- Файлоподібний об’єкт - дзвінок, sys.stdin.read()
щоб прочитати все.input(prompt)
- передайте йому необов'язковий запит на вихід, він читає від stdin до першого нового рядка, який він викреслює. Вам доведеться робити це неодноразово, щоб отримати більше рядків, наприкінці введення він піднімає EOFError. (Мабуть, це не чудово для гри в гольф.) У Python 2 це так rawinput(prompt)
.open(0).read()
- У Python 3 вбудована функція open
приймає дескриптори файлів (цілі числа, що представляють ресурси IO операційної системи), а 0 - дескриптор stdin
. Він повертає файлоподібний об'єкт на кшталт sys.stdin
- мабуть, найкраща ставка для гольфу. У Python 2 це так io.open
.open('/dev/stdin').read()
- аналогічно open(0)
, працює на Python 2 і 3, але не в Windows (або навіть Cygwin).fileinput.input()
- повертає ітератор по рядках у всіх файлах, перелічених у sys.argv[1:]
, або stdin, якщо вони не вказані. Використовуйте як ''.join(fileinput.input())
.І те, sys
і fileinput
імпорт повинен бути, відповідно, звичайно.
sys.stdin
приклади, сумісні з Python 2 і 3, Windows, UnixВам просто потрібно read
з sys.stdin
, наприклад, якщо ви дані по конвеєру стандартного введення:
$ echo foo | python -c "import sys; print(sys.stdin.read())"
foo
Ми бачимо, що sys.stdin
це в текстовому режимі за замовчуванням:
>>> import sys
>>> sys.stdin
<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>
Скажімо, у вас є файл, inputs.txt
ми можемо прийняти цей файл і виписати його назад:
python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
Ось повний, легко повторюваний демонстраційний файл, використовуючи два методи, вбудовану функцію input
(використання raw_input
в Python 2) та sys.stdin
. Дані немодифіковані, тому обробка - це не операція.
Для початку давайте створимо файл для входів:
$ python -c "print('foo\nbar\nbaz')" > inputs.txt
І за допомогою коду, який ми вже бачили, ми можемо перевірити, чи створили файл:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Ось довідка sys.stdin.read
з 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
в Python 2)Вбудована функція input
читає від стандартного вводу до нового рядка, який знімається (доповнюючи print
, який додає новий рядок за замовчуванням.) Це відбувається до тих пір, поки не отримає EOF (End Of File), після чого він піднімається EOFError
.
Отже, ось як ви можете використовувати input
в Python 3 (або raw_input
в Python 2) для читання з stdin - таким чином ми створюємо модуль Python, який ми називаємо stdindemo.py:
$ python -c "print('try:\n while True:\n print(input())\nexcept EOFError:\n pass')" > stdindemo.py
І давайте надрукуємо його назад, щоб переконатися, що це так, як ми очікуємо:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo.py
try:
while True:
print(input())
except EOFError:
pass
Знову input
читається до нового рядка і по суті знімає його з рядка. print
додає новий рядок. Тож як вони обидва модифікують вхід, їх зміни скасовуються. (Отже, вони по суті є доповненням один одного.)
І коли input
отримує символ кінця файлу, він викликає EOFError, який ми ігноруємо, а потім виходимо з програми.
І в Linux / Unix ми можемо передавати з cat:
$ cat inputs.txt | python -m stdindemo
foo
bar
baz
Або ми можемо просто перенаправити файл з stdin:
$ python -m stdindemo < inputs.txt
foo
bar
baz
Ми також можемо виконати модуль як сценарій:
$ python stdindemo.py < inputs.txt
foo
bar
baz
Ось довідка щодо вбудованого 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
Тут ми робимо демо-сценарій за допомогою sys.stdin
. Ефективним способом ітерації над файлоподібним об'єктом є використання файлоподібного об'єкта в якості ітератора. Додатковим методом запису в stdout з цього вводу є просто використання sys.stdout.write
:
$ python -c "print('import sys\nfor line in sys.stdin:\n sys.stdout.write(line)')" > stdindemo2.py
Роздрукуйте його назад, щоб переконатися, що він виглядає правильно:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo2.py
import sys
for line in sys.stdin:
sys.stdout.write(line)
І перенаправлення входів у файл:
$ python -m stdindemo2 < inputs.txt
foo
bar
baz
Гольф в команду:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Оскільки дескриптори файлів для stdin
і stdout
дорівнюють 0 і 1 відповідно, ми також можемо передавати їх open
в Python 3 (а не 2, і зауважимо, що нам ще потрібне 'w' для запису до stdout).
Якщо це працює у вашій системі, воно збрине більше символів.
$ python -c "open(1,'w').write(open(0).read())" < inputs.txt
baz
bar
foo
Python 2 також io.open
робить це, але імпорт займає набагато більше місця:
$ python -c "from io import open; open(1,'w').write(open(0).read())" < inputs.txt
foo
bar
baz
Один коментар пропонує зробити ''.join(sys.stdin)
гольф, але це насправді довше, ніж sys.stdin.read () - плюс Python повинен створити додатковий список в пам'яті (це str.join
працює, коли список не надається) - для контрасту:
''.join(sys.stdin)
sys.stdin.read()
Верхня відповідь пропонує:
import fileinput
for line in fileinput.input():
pass
Але, оскільки sys.stdin
реалізує файловий API, включаючи протокол ітератора, це точно так само, як це:
import sys
for line in sys.stdin:
pass
Ще одна відповідь говорить про це. Просто пам’ятайте, що якщо ви робите це в інтерпретаторі, вам потрібно буде зробити Ctrl- dякщо ви працюєте в Linux або Mac, або Ctrl- zв Windows (після Enter), щоб надіслати в процес символу кінця файлу. Крім того, ця відповідь говорить про те, print(line)
що додає '\n'
кінець до кінця - використовуйте print(line, end='')
натомість (якщо в Python 2 вам знадобиться from __future__ import print_function
).
Справжній випадок fileinput
використання для читання в серії файлів.
Відповідь, запропонована іншими:
for line in sys.stdin:
print line
дуже простий і пітонічний, але слід зазначити, що сценарій буде чекати, поки EOF перед початком ітерації в рядках введення.
Це означає, що tail -f error_log | myscript.py
лінії не оброблять, як очікувалося.
Правильним сценарієм для такого випадку використання буде:
while 1:
try:
line = sys.stdin.readline()
except KeyboardInterrupt:
break
if not line:
break
print line
ОНОВЛЕННЯ
З коментарів було зрозуміло, що тільки на python 2 може бути включена буферизація, так що ви закінчите чекати, коли буфер заповниться або EOF перед тим, як надрукувати друк.
for line in sys.stdin:
Картина НЕ чекати EOF. Але якщо ви протестуєте на дуже маленьких файлах, відповіді можуть бути буферизовані. Тестуйте з більшою кількістю даних, щоб побачити, чи читає він проміжні результати.
print line
не прокидається в 3.1.3, але так print(line)
і є.
for line in sys.stdin:
не "блокується до EOF". У Python 2 є помилка з попереднім читанням, яка затримує рядки до повного заповнення відповідного буфера. Це питання буферизації, яке не пов'язане з EOF. Для вирішення проблеми використовуйте for line in iter(sys.stdin.readline, ''):
(використовуйте io.open()
для звичайних файлів). Вам це не потрібно в Python 3.
Спираючись на всі анвери, що використовують sys.stdin
, ви також можете зробити щось подібне, щоб прочитати з файлу аргументу, якщо існує хоча б один аргумент, і повернутися до stdin в іншому випадку:
import sys
f = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
for line in f:
# Do your stuff
і використовувати його як як
$ python do-my-stuff.py infile.txt
або
$ cat infile.txt | python do-my-stuff.py
або навіть
$ python do-my-stuff.py < infile.txt
Це призвело б до того, що ваш сценарій Python поводитиметься як багато програм GNU / Unix, таких як cat
, grep
і sed
.
argparse
- це просте рішенняПриклад сумісний з обома версіями Python 2 та 3:
#!/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()
Цей сценарій можна запустити різними способами:
1. Використання stdin
echo 'foo bar' | ./above-script.py
або коротше, замінивши echo
на тут рядки :
./above-script.py <<< 'foo bar'
2. Використання аргументу імені файлу
echo 'foo bar' > my-file.data
./above-script.py my-file.data
3. Використання stdin
спеціального імені файлу-
echo 'foo bar' | ./above-script.py -
add_argument('--in'
а потім передати в сценарій та додати --in -
до командного рядка. PS in
- це не дуже добре ім'я для змінної / атрибута.
in
це не просто неправильне ім’я змінної, це незаконне. args.in.read()
призведе до помилки InvalidSyntax через in
зарезервоване ключове слово. Можна просто перейменувати, щоб infile
подобатися doc-аргументації
Наступний чіп коду допоможе вам (він прочитає все блокування stdin EOF
, в один рядок):
import sys
input_str = sys.stdin.read()
print input_str.split()
Я дуже вражений, поки ніхто не згадав про цей злом:
python -c "import sys; set(map(sys.stdout.write,sys.stdin))"
у python2 ви можете кинути set()
виклик, але це слово в будь-якому випадку
readlines
це розділення на рядки і join
знову? Можна просто написатиprint(sys.stdin.read())
write
повернення None
, а встановлений розмір ніколи не перевищуватиме 1 ( =len(set([None]))
)
Ви можете читати з stdin, а потім зберігати вхідні дані у "дані" таким чином:
data = ""
for line in sys.stdin:
data += line
data = sys.stdin.read()
без проблеми повторних струнних конкатенацій.
Читати з sys.stdin
, але щоб читати двійкові дані в Windows , потрібно бути особливо обережними, оскільки sys.stdin
вони відкриваються в текстовому режимі, і це може пошкодити \r\n
їх заміну \n
.
Рішення полягає в встановленні режиму бінарного, якщо виявлено Windows + Python 2, а на Python 3 використовується 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()
Я використовую наступний метод, він повертає рядок з stdin (я використовую його для розбору json). Він працює з pipe та prompt в Windows (ще не перевірений на Linux). При запиті два перерви рядка вказують на кінець введення.
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
Проблема у мене з рішенням
import sys
for line in sys.stdin:
print(line)
це те, що якщо ви не передасте будь-які дані в stdin, вони блокуються назавжди. Ось чому я люблю цю відповідь : перевірте, чи є якісь дані про stdin спочатку, а потім прочитайте їх. Ось що я закінчив робити:
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
виклику; або ви також можете зіткнутися з проблемами, якщо stdin підключений до файлу на повільному носії (мережа, компакт-диск, стрічка тощо). Ви сказали, що "якщо ви не передасте будь-які дані stdin, вони блокуються назавжди". це проблема , але я б сказав, що це особливість . Більшість програм CLI (наприклад cat
) працюють таким чином, і від них очікується. EOF - це єдине, від чого слід залежати, щоб виявити кінець вводу.
У мене виникли деякі проблеми, коли я працював над тим, щоб прочитати розетки, накладені на нього. Коли сокет закрився, він почав повертати порожній рядок в активний цикл. Тож це моє рішення для цього (яке я протестував лише в Linux, але сподіваюся, він працює у всіх інших системах)
import sys, os
sep=os.linesep
while sep == os.linesep:
data = sys.stdin.readline()
sep = data[-len(os.linesep):]
print '> "%s"' % data.strip()
Тож якщо ви почнете слухати сокет, він буде працювати належним чином (наприклад, в баші):
while :; do nc -l 12345 | python test.py ; done
І ви можете зателефонувати за допомогою telnet або просто навести браузер на localhost: 12345
З цього приводу:
for line in sys.stdin:
Я просто спробував це на python 2.7 (за чужою пропозицією) для дуже великого файлу, і я не рекомендую його саме з причин, зазначених вище (довгий час нічого не відбувається).
Я закінчив трохи пітонічне рішення (і воно працює на великих файлах):
with open(sys.argv[1], 'r') as f:
for line in f:
Тоді я можу запустити сценарій локально як:
python myscript.py "0 1 2 3 4..." # can be a multi-line string or filename - any std.in input will work
sys.stdin
скрипт як аргумент командного рядка.
sys.stdin
скрипт як аргумент командного рядка? Аргументи - це рядки, а потоки - файлоподібні об'єкти, вони не однакові.
sys.stdin
є об'єктом, подібним до файлів
Для Python 3 це було б:
# Filename e.g. cat.py
import sys
for line in sys.stdin:
print(line, end="")
Це в основному проста форма кота (1), оскільки вона не додає новий рядок після кожного рядка. Ви можете використовувати це (після того як ви позначили файл, який виконується, використовуючи chmod +x cat.py
такі:
echo Hello | ./cat.py
Використовуючи -c
команду як хитрий спосіб, замість того, щоб прочитати stdin
(а в деяких випадках більш гнучку), ви можете передати команду сценарію оболонки, а також команді python, поставивши команду sell у лапки в дужках, розпочату командою$
знаком.
напр
python3 -c "import sys; print(len(sys.argv[1].split('\n')))" "$(cat ~/.goldendict/history)"
Це підрахує кількість рядків з файлу історії goldendict.