Почему это работает в Python 3 IDLE в Windows, а не в терминале в Ubuntu? - PullRequest
1 голос
/ 07 декабря 2011

У меня есть программа, в которой я использую input() для ввода данных из STDIN.

Я использую ввод, чтобы прочитать первое слово из строки и использовать его как ключ словаря, при этом каждое последующее слово добавляется в список, который является значением упомянутого ключа.

Ввод в файл names.txt:

Victor Bertha Amy Diane Erika Clare
Wyatt Diane Bertha Amy Clare Erika
Xavier Bertha Erika Clare Diane Amy
Yancey Amy Diane Clare Bertha Erika
Zeus Bertha Diane Amy Erika Clare

Amy Zeus Victor Wyatt Yancey Xavier
Bertha Xavier Wyatt Yancey Victor Zeus
Clare Wyatt Xavier Yancey Zeus Victor
Diane Victor Zeus Yancey Xavier Wyatt
Erika Yancey Wyatt Zeus Xavier Victor

Так, например, men["Victor"] = ["Bertha","Amy","Diane","Erika","Clare"].

Код находится в файле GS.py (реализация Gale-Shapley):

if __name__ == "__main__":

    ## Data Dictionary

    ''' Name : Preferences '''
    men = dict()
    women = dict()

    ''' List of unmatched men '''
    freeMen = list()

    ''' Name : How far down in preferences '''
    count = dict()

    ''' Name : Current Match '''
    wife = dict()
    husband = dict()

    ## Reading Input
    data = input("").split("\n")
    print(data)
    readingMen = True
    for l in data:
        line = l.split()
        print(line)
        if len(line) > 1:
            newPerson = line[0]
            newPersonPreferences = list()
            for i in range(1,len(line)):
                newPersonPreferences.append(line[i])
            if readingMen:
                print("man")
                print(newPersonPreferences)
                men[newPerson] = newPersonPreferences
                wife[newPerson] = 0
                count[newPerson] = 0
                freeMen.append(newPerson)
            else:
                print("woman")
                print(newPersonPreferences)
                women[newPerson] = newPersonPreferences
                husband[newPerson] = 0
        elif len(line) == 1:
            raise IOError(l + "\nis an invalid line.")
        else:
            readingMen = False

    ## Proposing
    while len(freeMen) != 0:
        m = freeMen[0]
        w = men[m][count[m]]
        count[m] += 1
        if husband[w] == 0:
            husband[w] = m
            wife[m] = w
            freeMen.remove(m)
        else:
            try:
                if women[w].index(husband[w], women[w].index(m)):
                    freeMen.append(husband[w])
                    wife[husband[w]] = 0
                    husband[w] = m
                    wife[m] = w
                    freeMen.remove(m)
            except ValueError:
                pass

    ## Match Printing
    print()
    for m in wife:
        print(m, wife[m])

При использовании IDLE в Windows я просто вставляю содержимое этого файла и нажимаю ввод, и он работает.

Но используя Ubuntu, я делаю python3 GS.py < names.txt и получаю это:

me@glados:~$ python3 GS.py < names.txt
['Victor Bertha Amy Diane Erika Clare']
['Victor', 'Bertha', 'Amy', 'Diane', 'Erika', 'Clare']
man
['Bertha', 'Amy', 'Diane', 'Erika', 'Clare']
Traceback (most recent call last):
  File "GS.py", line 83, in <module>
    if husband[w] == 0:
KeyError: 'Bertha'

(отредактировано) Теперь, когда я делаю cat names.txt | python3 GS.py, я получаю это:

ajg9132@glados:~$ cat names.txt | python GS.py
Traceback (most recent call last):
  File "GS.py", line 50, in <module>
    data = input("").split("\n")
  File "<string>", line 1
    Victor Bertha Amy Diane Erika Clare
                ^
SyntaxError: invalid syntax

Я понятия не имею, что делать - как-то неосведомлен относительно ввода / вывода. Любая помощь?

Редактировать заметку: Я думал, что две разные команды bash, которые я дал, были эквивалентны, но опять же, я полный нуб, поэтому объяснение, почему они разные, тоже поможет ...

Чтобы прояснить неоднозначность, это для домашней работы Алго ... (грустно, что я понимаю алгоритм, но не детали низкоуровневой ОС), и мне нужно иметь конкретную схему ввода и вывода. например,

spock $ java GS
Victor Bertha Amy Diane Erika Clare
Wyatt Diane Bertha Amy Clare Erika
Xavier Bertha Erika Clare Diane Amy
Yancey Amy Diane Clare Bertha Erika
Zeus Bertha Diane Amy Erika Clare

Amy Zeus Victor Wyatt Yancey Xavier
Bertha Xavier Wyatt Yancey Victor Zeus
Clare Wyatt Xavier Yancey Zeus Victor
Diane Victor Zeus Yancey Xavier Wyatt
Erika Yancey Wyatt Zeus Xavier Victor

Victor Amy
Wyatt Clare
Xavier Bertha
Yancy Erika
Zeus Diane
spock $

Единственная причина, по которой я этого не делал, заключалась в том, что вставка нескольких строк текста в PuTTY заставила bash интерпретировать каждую строку как команду. Я даже не могу.

1 Ответ

3 голосов
/ 07 декабря 2011

Значение input() изменилось.

В Python 3.2: http://docs.python.org/py3k/library/functions.html#input

В Python 2.7.2: http://docs.python.org/library/functions.html#input

Вы можете увидеть это намного проще с двумя небольшими программами тестирования. Единственное отличие состоит в том, что один использует интерпретатор Python 2.7, а другой - интерпретатор Python 3.2:

$ cat input27.py 
#!/usr/bin/python2.7
data = input("")

for l in data.split("\n"):
    print(l)
$ cat input32.py 
#!/usr/bin/python3.2
data = input("")

for l in data.split("\n"):
    print(l)
$ ./input27.py < names.txt 
Traceback (most recent call last):
  File "./input27.py", line 2, in <module>
    data = input("")
  File "<string>", line 1
    Victor Bertha Amy Diane Erika Clare
                ^
SyntaxError: invalid syntax
$ ./input32.py < names.txt 
Victor Bertha Amy Diane Erika Clare
$ 

Обратите внимание, что, хотя версия Python 3.2 не выдает ошибок, она также не печатает все строки в names.txt, как можно было бы ожидать.

Я не думаю, что метод input() стоит использовать. Проще было бы использовать новомодный подход for line in file: вместо:

$ cat fixed_input27.py 
#!/usr/bin/python2.7

import sys

for line in sys.stdin:
    print(line.split()[0])
$ cat fixed_input32.py 
#!/usr/bin/python3.2

import sys

for line in sys.stdin:
    print(line.split()[0])
$ ./fixed_input27.py < names.txt 
Victor
Wyatt
Xavier
Yancey
Zeus
Amy
Bertha
Clare
Diane
Erika
$ ./fixed_input32.py < names.txt 
Victor
Wyatt
Xavier
Yancey
Zeus
Amy
Bertha
Clare
Diane
Erika
$ 

(Я удалил одну пустую строку из names.txt, потому что она вызвала ошибку этой простой программы. На самом деле это не будет проблемой в вашей полноценной программе, потому что вы правильно обрабатываете пустую строку.)

Я не могу объяснить, почему input() работал под Windows, но input() выглядит как достаточно ужасный интерфейс (который считал, что запуск пользовательского ввода через eval был хорошей идеей ?!? sheesh) просто переписать это.

Обновление

Хорошо, я был достаточно заинтригован, чтобы полностью решить эту проблему. Я забрал весь ваш код отладки и переключился на for l in sys.stdin: подход:

$ ./GS.py 
Victor Bertha Amy Diane Erika Clare
Wyatt Diane Bertha Amy Clare Erika
Xavier Bertha Erika Clare Diane Amy
Yancey Amy Diane Clare Bertha Erika
Zeus Bertha Diane Amy Erika Clare

Amy Zeus Victor Wyatt Yancey Xavier
Bertha Xavier Wyatt Yancey Victor Zeus
Clare Wyatt Xavier Yancey Zeus Victor
Diane Victor Zeus Yancey Xavier Wyatt
Erika Yancey Wyatt Zeus Xavier Victor

Wyatt Clare
Xavier Bertha
Yancey Erika
Zeus Diane
Victor Amy
$ cat GS.py 
#!/usr/bin/python3.2

if __name__ == "__main__":
    import sys

    ## Data Dictionary

    ''' Name : Preferences '''
    men = dict()
    women = dict()

    ''' List of unmatched men '''
    freeMen = list()

    ''' Name : How far down in preferences '''
    count = dict()

    ''' Name : Current Match '''
    wife = dict()
    husband = dict()

    ## Reading Input
    readingMen = True
    for l in sys.stdin:
        line = l.split()
        if len(line) > 1:
            newPerson = line[0]
            newPersonPreferences = list()
            for i in range(1,len(line)):
                newPersonPreferences.append(line[i])
            if readingMen:
                men[newPerson] = newPersonPreferences
                wife[newPerson] = 0
                count[newPerson] = 0
                freeMen.append(newPerson)
            else:
                women[newPerson] = newPersonPreferences
                husband[newPerson] = 0
        elif len(line) == 1:
            raise IOError(l + "\nis an invalid line.")
        else:
            readingMen = False

    ## Proposing
    while len(freeMen) != 0:
        m = freeMen[0]
        w = men[m][count[m]]
        count[m] += 1
        if husband[w] == 0:
            husband[w] = m
            wife[m] = w
            freeMen.remove(m)
        else:
            try:
                if women[w].index(husband[w], women[w].index(m)):
                    freeMen.append(husband[w])
                    wife[husband[w]] = 0
                    husband[w] = m
                    wife[m] = w
                    freeMen.remove(m)
            except ValueError:
                pass

    ## Match Printing
    print()
    for m in wife:
        print(m, wife[m])

$ 

Обратите внимание, что вы должны нажать ^D, когда закончите вставку во ввод, если вы запустите его таким образом. (Я сильно предпочитаю перенаправление ввода-вывода ./GS.py < names.txt, но если ваш профессор будет копировать и вставлять, то убедитесь, что ваш профессор знает, что нужно нажать ^D, чтобы сигнализировать о конце ввода.)

...