V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
bbxiong
V2EX  ›  Python

Python 异常处理风格

  •  
  •   bbxiong · 2020-11-20 12:21:00 +08:00 · 2405 次点击
    这是一个创建于 1253 天前的主题,其中的信息可能已经有所发展或是发生改变。

    selenium api 基本全都会抛异常

    比如

    if driver.find_element_by_class_name("general-error"): print("登录错误")

    必须要写成如下 try: if driver.find_element_by_class_name("general-error"): print("登录错误") except: pass

    所有常用 api 都会抛出异常,每个 find_element_by_xxx 都必须放在 try except 封装成函数,显得代码臃肿不堪...

    是不是我的风格有问题,请教下大家都怎么处理这种情况的.

    第 1 条附言  ·  2020-11-20 13:00:17 +08:00

    循环登录代码

    
    while True:    
        if driver.find_element_by_class_name("loaderIcon"):
            print("网页加载中")
            time.sleep(1)
        elif driver.find_element_by_class_name("ut-tab-bar"):
            print("登陆成功")
            return True
        elif driver.find_element_by_class_name("btn-standard"):
            driver.find_element_by_class_name("btn-standard").click()
            WebDriverWait(driver, 1).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "btnLogin")))
            if driver.find_element_by_id("btnLogin"):
                print("找到 btnLogin")
                break
        elif driver.find_element_by_id("email"):
            driver.find_element_by_id("email").send_keys(username)
            driver.find_element_by_id("password").send_keys(pwd)
            driver.find_element_by_id("btnLogin").click()
        elif driver.find_element_by_id("btnSendCode"):
            print("等待输入验证码")               
        elif driver.find_element_by_class_name("general-error"):
            print("登陆错误!!!")
            break
            
    

    必须要吧每个find_element_xxx 封装函数,内部try catch处理,代码量增加不少

    while True:
        if 是否加载中():
            print("网页加载中")
            time.sleep(1)
        elif 登陆成功():
            print("登陆成功")
            return True
        elif 是否登录界面():
            driver.find_element_by_class_name("btn-standard").click()
            WebDriverWait(driver, 1).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "btnLogin")))
            if driver.find_element_by_id("btnLogin"):
                print("找到 btnLogin")
                break
        elif 是否输入用户名密码界面():
            driver.find_element_by_id("email").send_keys(username)
            driver.find_element_by_id("password").send_keys(pwd)
            driver.find_element_by_id("btnLogin").click()
        elif 是否验证码界面():
            print("等待输入验证码")
        elif 登陆错误(1):
            print("登陆错误!!!")
            break
            
    
    8 条回复    2020-11-25 19:24:09 +08:00
    imn1
        1
    imn1  
       2020-11-20 12:32:26 +08:00
    这种情况我选择换个写法,例如其他模块

    实际上我都没用过 selenium api,都不知道会抛出异常,我是获取 content 然后用其他 parser 模块处理的

    如果不可避免非要用某个模块,它又容易抛出异常,我会写个类继承过来,或者闭包,把异常集中处理
    happinessnch
        2
    happinessnch  
       2020-11-20 12:37:47 +08:00
    异常处理,和业务逻辑没有关系,咋一看好像很臃肿,好多地方要 try catch,
    实际上异常处理多了慢慢也就习惯了,根据不同异常做一些定制化的处理,
    绝大多数异常是不应该直接 pass 的,但是实际开发时,每个异常都处理确实有点过于苛求了。
    no1xsyzy
        3
    no1xsyzy  
       2020-11-20 14:25:40 +08:00
    这个是设计问题,不过你这边似乎也可以更正交地抽象

    def finds(driver, **kwargs):
       try:
         return driver.find_element(...) # TODO: implement it
       except:
         return None

    这样的话你以后就可以
    if finds(driver, class_name="loaderIcon"):
      ...
    elif finds(driver, class_name="ut-tab-bar"):
      ...
    ...
    no1xsyzy
        4
    no1xsyzy  
       2020-11-20 14:28:58 +08:00
    @happinessnch BTW 如果逻辑上确实应不处理,我推荐 with contextlib.suppress
    如果暂时不作处理,我推荐 except: pass # TODO: handle this
    bbxiong
        5
    bbxiong  
    OP
       2020-11-20 15:13:14 +08:00
    @no1xsyzy 这种设计方式用起来比较方便,其实我奇怪的为啥 selenium 设计这些 api 要抛异常,而不是找不到返回 None
    imn1
        6
    imn1  
       2020-11-20 15:24:16 +08:00
    @bbxiong #5
    模块一般是通用的,泛考虑

    例如某个 exif 模块,里面严格执行 exif 规范,dump 的时候一个值错了就会抛异常
    本来 exif 有几百条,一条错误并不影响其他读取,也不影响图片本身显示,批量处理(上千个图片)遇到错误可以跳过就行了,逐个处理异常确实麻烦
    但人家按照规范做,也不能说人家做错了,因为遵守规范总是正确立场,只能自己继承修改以适应自己的需求
    no1xsyzy
        7
    no1xsyzy  
       2020-11-20 22:38:38 +08:00
    @bbxiong 发现我可能单位写了一堆忘了发……
    应该它的这些 API 就是设计为链式调用的,那显然报一个“元素找不到”的错比“NoneType 没有此属性”的错更合理。
    不过,我设计的话会设计两套 API,一个更简洁的引发异常,更啰嗦的给 None,形如 dct['key'] v.s. dct.get('key')
    或者提供一个参数来表示默认值,不提供就引发异常,形如 dct.pop('key', None) v.s. dct.pop('key')
    peckey
        8
    peckey  
       2020-11-25 19:24:09 +08:00
    find_elements_by_xxx 不会抛出异常
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4852 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 05:39 · PVG 13:39 · LAX 22:39 · JFK 01:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.