美文网首页
getopt 模块使用注意事项(踩坑日记)

getopt 模块使用注意事项(踩坑日记)

作者: MangfuStudio | 来源:发表于2018-11-22 02:50 被阅读0次

    前言

    最近和我们学校的IT社长写一个网页下载工具,今天刚更新命令行参数功能,踩了坑getopt模块中的一个坑,main.py文件完整源码如下

    # coding=utf-8
    
    import sys
    import getopt
    from DownloadWebPage import DownloadWebPage
    
    
    # url = 'https://mbd.baidu.com/newspage/data/landingsuper?context=%7B%22nid%22%3A%22news_8912090858788091154%22%7D&n_type=0&p_from=1'
    
    def _usage() -> str:
        print("""
        Download WebPage Main Program
    
        -h,--help Display help.
        -e,--encoding Set encoding for website files recoding.
        -p,--path Set webpage all files main path.(Default on ./data)
        -s,--static Set webpage static files path.(Default on {path}/static)
        -t,--timeout Set request timeout.(Default 30sec)
    
        Examples:
            python main.py http://www.google.com
            python main.py http://www.google.com -t 60
            python main.py http://www.google.com --path ./website
            python main.py http://www.google.com --path ./website --static /res
        
        """)
    
    
    def main(argv):
        try:
            opts, args = getopt.getopt(argv, "he:t:p:s:", [
                                       "encoding=", "timeout=", "path=", "static=", ])
        except getopt.GetoptError as err:
            print(err)
            _usage()
            sys.exit()
        if len(args) < 1:
            print('[!!!] No url!')
            sys.exit()
            # assert False
        else:
            url = args[0]
            if len(opts) < 1:
                path = static = encoding = timeout = None
            for opt, value in opts:
                if opt in ('-h', '--help'):
                    _usage()
                    sys.exit(0)
                path = value if opt in ('-p', '--path') else None
                static = value if opt in ('-s', '--static') else None
                encoding = value if opt in ('-e', '--encoding') else None
                timeout = int(value) if opt in ('-t', '--timeout') else None
            dwp = DownloadWebPage(url, path, static, encoding, timeout)
            dwp.save()
    
    
    # 当为主程序入口
    if __name__ == '__main__':
        if len(sys.argv) < 2:
            _usage()
            sys.exit()
        main(sys.argv[1:])
    

    以上逻辑看起来很完美(这里不得不佩服社长,代码敲的比我六)。

    更新完后第一时间测试下
    编码问题,意料之中
    试下刚更新的命令行参数功能,加个 utf-8 完成测试

    这次结果出乎意料,加了utf-8一样报错,开始各种测试(为什么不怀疑是解码的问题?因为之前的编码问题已经解决,加utf-8是可以解决的),最后发现是getopt模块的问题

    开始测试getopta模块

    嗯,为了不影响开发分支,单独开一个文件 test.py
    源码如下

    import getopt
    import sys
    
    def _usage():
        print(
        """
        -h,--help   Help information
        -d,--delete Delete file
        -a,--add    Add file
        """
        )
    
    def main():
        opts,args = getopt.getopt(sys.argv[1:], "hd:a:", ["help","delete=","add="])
        print("opts:",opts)
        print("srgs:",args)
    
    if __name__ == "__main__":
        main()
    

    大概测试了一遍,发现是参数顺序问题

    getopt.getopt()会同时返回两个列表
    一个列表由参数的 "选项/值" 所组成的元组组成例如-d是删除文件按的一个选项 python test.py -d test.txt -a new.txt ,处理后会返回 [('-d','test.txt'), ('-a','new.txt')]
    另一个列表由无选项参数组成,例如python main.py file.txt file2.txt,处理后会返回 ['file.txt', 'file2.txt']

    小提示:

    在以下测试中 getopt.getopt()
    返回的带选项的参数列表的名称为 opts
    返回的不带选项的参数列表为 args

    如果把带选项的参数放到开头,无选项参数放到末尾,getopt运行正确


    但要是反过来就要命了 从上方图片可以看到 ,getopt把-e delete_file.txt 作为不带选项的参数来处理,这并不是我们期待的结果,说了这么多,没有解决方法不都是废话么?

    解决方法

    解决方法很简单,使用getopt.gnu_getopt()函数就行了。

    看文档

    这个函数像 getopt() 一样工作,除了默认使用GNU样式扫描模式。这意味着选项和非选项参数可以混合。一旦遇到非选项参数,getopt() 函数就停止处理选项。
    如果选项字符串的第一个字符是“+”,或者如果设置了环境变量POSIXLY_CORRECT,那么一旦遇到非选项参数,选项处理就会停止。

    gun_getopt()允许参数混合,嗯。。。。光速修改替换getopt()gun_getopt()

    import getopt
    import sys
    
    
    def _usage():
        print(
        """
        -h,--help   Help information
        -d,--delete Delete file
        -a,--add    Add file
        """
        )
    
    def main():
        # getopt() -> gun_getopt()
        opts,args = getopt.gnu_getopt(sys.argv[1:], "hd:a:", ["help","delete=","add="])
        print("opts:",opts)
        print("srgs:",args)
    
    
    if __name__ == "__main__":
        main()
    
    修改后的运行结果

    哦~~ 完美

    总结

    又是一起不熟悉模块而熬夜改BUG的血案

    相关文章

      网友评论

          本文标题:getopt 模块使用注意事项(踩坑日记)

          本文链接:https://www.haomeiwen.com/subject/zxlkqqtx.html