为什么在Windows的Python 3 IDLE中可以,但在Ubuntu终端中不行?
我有一个程序,里面用 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])
在 Windows 上用 IDLE 时,我只需把这个文件的内容粘贴进去,然后按回车,就能正常工作。
但在 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 个回答
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
处理是个好主意呢?!真是的),所以我决定重写它。
更新
好吧,我对这个问题产生了足够的兴趣,决定彻底解决它。我把你们的调试代码都去掉了,改用了 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
来表示输入结束。)