夫学须志也,才须学也,非学无以广才,非志无以成学。——诸葛亮
生活有度,自得慈铭 ——杜锦阳
今天新来的小弟安装环境遇到个莫名其妙的问题:
AttributeError: 'Module' object has no attribute 'STARTF_USESHOWINDOW'
其它小伙伴好像都没遇到过,后来发现,应该是系统的问题,因为还出现了字节混乱的错误: UNICODEENCODEERROR:‘ascii’ code can't encode...
这个先不提,我们先来看看下面的错误: STARTF_USESHOWINDOW
因公司信息,所以打上马赛克了。
百度了一会,发现网上解决方案都不靠谱。
出错原因:使用了subprocess模块,系统找不到这个模块。
你可以做个测试:在python下输出subprocess也会报这个错。
后来想到有可能系统环境的问题和模块代码引起,起初是替换了Lib\site-packages\matplotlib\compat
下的subprocess.py
,后来想到这是子模块,于是再替换了Lib\下的 subprocess.py
,再运行,一切正常。
国内外论坛都没找到相关的解释,后来去翻了源码才知道了原因,Cmd是WIN下命令符,pyc是编译后运行的,和JAVA一样,一次编译多处运行,如果出现这个错误的小伙伴可以找这几个地方替换下,或者直接拿可运行版本的丢进去覆盖下。
我们来翻看一下:
if mswindows:
import threading
import msvcrt
import _subprocess
class STARTUPINFO:
dwFlags = 0
hStdInput = None
hStdOutput = None
hStdError = None
wShowWindow = 0
class pywintypes:
error = IOError
else:
import select
_has_poll = hasattr(select, 'poll')
import fcntl
import pickle
# When select or poll has indicated that the file is writable,
# we can write up to _PIPE_BUF bytes without risk of blocking.
# POSIX defines PIPE_BUF as >= 512.
_PIPE_BUF = getattr(select, 'PIPE_BUF', 512)
此处是引入了 import _subprocess
模块,也就是说 subprocess.py -> _subprocess
然后定位到:
if mswindows:
#
# Windows methods
#
在这下面找到:
def _execute_child(self, args, executable, preexec_fn, close_fds,
cwd, env, universal_newlines,
startupinfo, creationflags, shell, to_close,
p2cread, p2cwrite,
c2pread, c2pwrite,
errread, errwrite):
"""Execute program (MS Windows version)"""
if not isinstance(args, types.StringTypes):
args = list2cmdline(args)
# Process startup details
if startupinfo is None:
startupinfo = STARTUPINFO()
if None not in (p2cread, c2pwrite, errwrite):
startupinfo.dwFlags |= _subprocess.STARTF_USESTDHANDLES
startupinfo.hStdInput = p2cread
startupinfo.hStdOutput = c2pwrite
startupinfo.hStdError = errwrite
if shell:
startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = _subprocess.SW_HIDE
comspec = os.environ.get("COMSPEC", "cmd.exe")
args = '{} /c "{}"'.format (comspec, args)
if (_subprocess.GetVersion() >= 0x80000000 or
os.path.basename(comspec).lower() == "command.com"):
# Win9x, or using command.com on NT. We need to
# use the w9xpopen intermediate program. For more
# information, see KB Q150956
# (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp)
w9xpopen = self._find_w9xpopen()
args = '"%s" %s' % (w9xpopen, args)
# Not passing CREATE_NEW_CONSOLE has been known to
# cause random failures on win9x. Specifically a
# dialog: "Your program accessed mem currently in
# use at xxx" and a hopeful warning about the
# stability of your system. Cost is Ctrl+C wont
# kill children.
creationflags |= _subprocess.CREATE_NEW_CONSOLE
看到这里,应该不难发现,CREATE_NEW_CONSOLE
是如何触发的。
再来看下main方法的测试入口:
"""
KARL-Dujinyang
QQ:309933706
"""
if __name__ == "__main__":
if mswindows:
_demo_windows()
else:
_demo_posix()
mswindows
在我们文章开头代码中已经提及了,测试的可以拿到此处代码进行测试:
mswindows = (sys.platform == "win32")
_demo_windows
方法的定义:
def _demo_windows():
#
# Example 1: Connecting several subprocesses
#
print "Looking for 'PROMPT' in set output..."
p1 = Popen("set", stdout=PIPE, shell=True)
p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE)
print repr(p2.communicate()[0])
#
# Example 2: Simple execution of program
#
print "Executing calc..."
p = Popen("calc")
p.wait()
可以看出,这里是由 OPEN->CLOSE
所引起的问题。如果出现这个错误的小伙伴可以找这几个地方替换下,或者直接拿可运行版本的丢进去覆盖下,也可以找我拿下源码覆盖,后面如果有时间我会上传到一份到CSDN上。
|| 版权声明:本文为博主杜锦阳原创文章,转载请注明出处。