动机
受这个问题的启发 - OP正在使用
urlopen()
并且意外地传递了sys.argv
列表而不是字符串作为url
。抛出此错误消息:
属性错误:“列表”对象没有属性“超时”
由于
urlopen
的编写方式,错误消息本身和回溯信息不是很丰富,可能很难理解,尤其是对于Python新手来说:
Traceback (most recent call last):
File "test.py", line 15, in <module>
get_category_links(sys.argv)
File "test.py", line 10, in get_category_links
response = urlopen(url)
File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 154, in urlopen
return opener.open(url, data, timeout)
File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 420, in open
req.timeout = timeout
AttributeError: 'list' object has no attribute 'timeout'
问题
这是我正在使用的缩短的代码:
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
import sys
def get_category_links(url):
response = urlopen(url)
# do smth with response
print(response)
get_category_links(sys.argv)
我正在尝试思考是否可以使用 PyCharm 等智能 IDE、flake8
或
pylint
等静态代码分析工具,或者使用类型注释 等语言功能来静态捕获此类错误。 但是,我没能发现问题:
flake8
和
pylint
来说可能太具体了 - 他们不会警告问题
PyCharm
不会警告
sys.argv
被传递到
urlopen
,尽管如此,如果您“跳转到
sys.argv
的源”,它被定义为:
argv = [] # real value of type <class 'list'> skipped
将函数参数注释为字符串并传递sys.argv
,也不会出现警告:
def get_category_links(url: str) -> None:
response = urlopen(url)
# do smth with response
get_category_links(sys.argv)
问题
是否可以静态地捕获这个问题(无需实际执行代码)?
mypy 来分析您的代码,而不是保持特定于编辑器。这样,它将在所有开发环境中运行,而不仅仅是那些使用 PyCharm 的环境。
from urllib.request import urlopen
import sys
def get_category_links(url: str) -> None:
response = urlopen(url)
# do smth with response
get_category_links(sys.argv)
response = urlopen(sys.argv)
mypy针对上述代码指出的问题:
error: Argument 1 to "get_category_links" has incompatible type List[str]; expected "str"
error: Argument 1 to "urlopen" has incompatible type List[str]; expected "Union[str, Request]"
Mypy 这里可以猜测
sys.argv
的类型,因为它在其存根文件中定义。目前,一些标准库模块仍然在
typeshed
中缺失,因此您必须贡献它们或忽略相关错误,直到它们被添加:-)。何时运行 mypy?
import sys
from urllib2 import urlopen
def get_category_links(url):
if type(url) != type(""): #Check if url is string or not
print "Please give string url"
return
try:
response = urlopen(url)
# do smth with response
print(response)
except ValueError: #If url is string but invalid
print "Bad URL"
get_category_links(sys.argv)