精华内容
下载资源
问答
  • 经过数个ERP/MIS项目的开发,列举常见的问题与错误,共勉励。 1 界面代码与逻辑代码混淆 在项目的开始,一般都可以做到界面与逻辑的分离,界面只做数据绑定,业务逻辑则实现客户要求的计算。 WinForms中的Binding...

    经过数个ERP/MIS项目的开发,列举常见的问题与错误,共勉励。

    1 界面代码与逻辑代码混淆

    在项目的开始,一般都可以做到界面与逻辑的分离,界面只做数据绑定,业务逻辑则实现客户要求的计算。

    WinForms中的BindingSource和Web中的ObjectDataSource,可以实现对object绑定到界面控件属性的功能。

    这会带来极大的方便,降低程序的维护代价,做到低耦合。举例说明
    采购单Sales Order的价格公式

    Sales Order Price Amout=Item Price + Tax + Additional charge

    采购单物料总金额=物料金额+ 税金+ 附加费用(运费,保险费…)

    Tax 税金的计算,一般会根据物料的总金额,乘以百分比即可,是由系统自动运算的。
    现在改需求了,客户不需要考虑税金,免税,这样公式即变化为
    Sales Order Price Amout=Item Price +  Additional charge
    公式中少了一项内容。如果界面和逻辑严格分离,这里只需要改一下逻辑即可,不需要改动界面。当项目中发生这样的需求改动越来越多时,业务与界面分离的好处会大大降低维护的代价。

    2 不能适应需求变化

    做ERP/MIS软件,需求不可能没有变化。即使是实施之后,修改起来比较麻烦,客户愿意出钱,也需要改动原来需求。

    常见的需求更改:增加数据库字段,添加更多的明细表记录。增加数据库字段是经常遇到的,如果你的数据绑定代码是手写的,或是拼凑SQL语句,这回你可真要痛苦一下,加一个字段会令你重新检查所有的数据读写代码。另外,界面也要添加控件,绑定实体的属性。我的经验是,设计代码生成可靠,生成数据读写代码,当增加数据库字段后,只需要重新生成数据读写代码,非常轻松的维护代码。如果应用到ORM框架和数据绑定,增加字段只需要改一下界面即可,会更轻松。

    3 缺乏足够的逻辑验证Validation代码

    用户的输入总是有各种问题的,要常常记得验证客户的输入。设计自定义的控件,NumbericInputBox,CurrencyBox专有来输入数值数据,货币数据,可以减少很多验证代码。其次,在保存数据时,要验证数据的主键是否重复,检查外键的字段是否已经存在,这些检查是必要,尽管SQL会帮忙你找出错误,但是,终究是你没有写验证的原因。
    ERP/MIS开发,验证也是体现逻辑的一个地方。工作单过帐时要检查物料清单是否有效,工序是否已经确认,下销售单时,要判断客户的信用额是否超过预定的额度,大量的验证代码存在于ERP/MIS系统中,请添加足够的验证代码,而不是假设用户的输入或系统的判断是正确的。

    4 没有始终贯彻接口与实现分离

    在项目开发前中期,我们预定接口与实现一定要分离,像这样的
    public interface IAccountManager {  }
    public interface AccountManager  {  }
    调用方法
    IAccountManager  accountManager = ClientProxyFactory.CreateProxyInstance<IAccountManager >();

    可是,当项目处于不停的维护和修改的状态时,我们常常会偷懒,写出这样的代码
    IAccountManager accountManager =new AccountManager ();

    这种偷懒也是要付出代价的,前一种标准的写法,可以实现WCF,.NET Remoting通信框架的互换,而不影响任何代码,CreateProxyInstance这个方法里面,可以做的事情太多了。前一种写法,可以实现cache缓存接口实现类,而后一种方法则无法做到,前一种方法,可以减少编译时的依赖,完全在运行时才解析出需要的类型。

    5 对部署/应用环境没有做周全的考虑

    我们开发的代码,没有对代码的执行环境做很全面的检测。比如,客户的电脑没有安装.NET 3.0/3.5,我们写的Linq代码就会出错,如果没有安装.NET 4.0,用到并行类的方法也会出错。如果客户安装的Crystal Report的版本与我们开发时引用的版本不一致,代码执行时,会发生FileNotFoundedException异常,Report Viewer控件也是如此。客户的机器上没有安装Reporting Services,而我们的代码也没有检查Reporting Services服务是否存在,就开始读取它的报表项来呈现报表。如果竞争对手想试用你的ERP/MIS系统,把你的软件装在虚拟机中,对于依靠检测系统日期来判断是否过期的验证方式,则在虚拟机中改日期后,你的对手可以有足够的时间来消化学习你的系统。
    对此,要充分考虑软件的运行环境,做出判断以减少低级错误。

     

    6 对系统的更改和维护缺少设计规范(Design Specifications)

    你的系统维护是否是这样的,客户说要改,你就马上开始改代码。老板说要改一个地方,你也毫不怨言的打开VS.NET,开始修改代码。这样是可以的,但不可取。客户要改,尽管他和老板的关系好,但你也要先记下来,当面沟通后,事后写个邮件给你的上司,说明有哪些任务要做,有哪些修改。这样做,一来是因为你的上司给你发工资,你的工作只对上司负责,不是对客户负责,二来是,记下来后,再书面确认一下,以防止客户抵赖或是沟通不充分。在不需要交修改维护费用的情况下,客户要改的东西实在是太多了,有时候可能客户因为心情不好,把你叫过去说半天,改这里改那里,等下班了回去之后,客户他自己都忘记了要改什么了。沟通不充分的问题,主要是怕你误解了客户的意思,或是说客户没有说明白,既然客户是上帝,上帝是没有错的,那就是你的理解错了。所以,事后用书面形式再确认一下,会是增加沟通效果有好办法。这个维护修改的书面表达形式,就是要说的Design Specifications。把客户要改的东西,放到标准的Design Specifications模板文件中去,打印出来,拿给客户签个名,他会很重视自己的说过的修改。我有曾见过厉害的客户,他明明知道这个修改有些不合理,但是工作完成后,等验收时,完全是按照他的意思做的,他也表示满意。这就叫做信誉,下次再找我改需求,我肯定会很乐意。

     

    7 没有隔离第三方软件/控件供应商的组件变化

    在我们的项目中,常常会引用一些第三方的控件,因为他们强大,好用。但是,我们还需要自定义一套控件,用来隔离这种第三方控件的变化。第三方的控件供应商,会常常更新它的API,属性和方法,如果项目中缺少这种隔离,则控件一变,我们的所有代码都需要改变。举例说明,第三方控件WebGrid,有一个属性DisplayLayout,用于显示界面元素,我们在ERP/MIS中大量应用到这个属性。如果有一天,WebGrid把这个属性DisplayLayout改名为Layout,这下惨了,我们要改的代码太多了。推荐一个好办法是,重新这个第三方控件,加入我们的自定义属性
    public class Grid:WebGrid
    {

          pubic DisplayLayoutDisplayLayout;
    }
    当第三方的组件WebGrid把属性DisplayLayout改名为Layout,我们只需要这样做

    public class Grid:WebGrid
    {

          pubic Layout  DisplayLayout;
    }
    引用此控件的ERP/MIS代码则不需要任何变化,即可适应第三方软件的API的变化。

    8 报表开发与定制缺少必要的文档,公式和字段来源说明

    这是我们公司ERP维护的一个困境,有大量的客户会要求实施人员帮忙定制一些报表。随着时间的推移,ERP维护人员走了一批又一批,当初定制报表的存储过程,修改的目的,文档也丢失了,很难从几百上千行的代码中,找到合适的理由,为什么要这样修改。工作多年后,虽然习惯了看没有文档的代码,习惯看没有说明和注释的代码,只好硬着头皮帮忙客户找SQL,找报表的存储过程,一点点的修复bug。ERP/MIS中,与数据有关的bug会占有很大的比例,就因为数据的不同,程序无法作出适当的处理,出错。虽然现在已经用建立Sharepoint建立了以客户为目录的共享文件夹,但要维护好客户的需求记录,还真不容易做到。

     

    9 没有考虑数据库的可移植性

    我一直都很佩服Oracle的市场宣传做的很好,从开发人员到工程师,从老板到销售助理,一提到数据库,都会提到Oracle。有时候销售助理,会大肆宣扬Oracle的好处,甚至比开发人员还懂得多。也有的客户,指定只用Oracle,拒绝用其它的数据库,没有任何理由。所以,如果是做一个长期的产品,还是要考虑将来数据库移植的问题。数据访问,要用通用的DbConnection,DbCommand,DbDataAdapter,或是用ORM;少用存储过程,多用程序代码来实现逻辑。在系统开发时,开发人员常常只是理论上实现了多种数据库的支持,真要到真实的多种数据库平台中跑一下的时候,问题会接二连三的来了。以SQL语句,选择前十行数据为例子
    MySQL 和PostgreSQL : SELECT * FROM emp limit 10
    Oracle :  SELECT * FROM emp WHERE rownum<=10
    SQL Server :  SELECT TOP 10  *  FROM  emp
    我的建议是,如果要支持多种数据库,尽早做规划,尽早建立真实的数据库环境测试。

    10 对命名规范(文件,控件,变量)不能始终坚持

    以举例为证,窗体类一般会在后面加个frm来表是是窗体类,如SalesOrderfrm,所有显示报表的窗体,后面加rpt,如SalesOrderrpt。 这里有个小技巧,为什么不是rptSalesOrder,而是SalesOrderrpt。这是为了在IDE的Solution Explorer视图中,以方便的看清同一组的窗体而以此命名的。如果我再加一个报表SalesOrderQuotationrpt,这样,在Solution Explorer视图中,这两个报表窗体是显示在一起的,方便查看。

    对于控件,请看下面的命名
    private EPN.WinUI.Editors.TextEditor txtRevisedBy;
    private EPN.WinUI.Misc.Label lblLastRevised;
    private EPN.WinUI.Editors.DateTimeEditor dteRevisedDate;
    private EPN.WinUI.Misc.Button btnPrint;

    txt表示TextEditor,btn表示Button,lbl表示Label.

    日期格式,有的地方是用yyyy-MM-dd,但是有的地方是yyyy/MM/dd,没有统一。

    价格Price字段的长度,是decimal(12,4), Amout合计字段的长度是decimal(16,4)
    对于这些规范,要始终的坚持。如果可能,可以开发一个Code Analysis规则,来自动分析程序集。

    转载于:https://www.cnblogs.com/JamesLi2015/archive/2011/08/26/2153986.html

    展开全文
  • 2.6.2 常见错误四:不注意收集异常事实,挖掘背后需求 18 2.7 现场调研阶段容易犯哪些错误?(三) 19 2.7.1 常见错误五:每天调研工作时间太长 19 2.7.2 常见错误六:聆听,而不是提供解决方案 20 2.8 现场调研...
  • 2.6.2 常见错误四:不注意收集异常事实,挖掘背后需求 18 2.7 现场调研阶段容易犯哪些错误?(三) 19 2.7.1 常见错误五:每天调研工作时间太长 19 2.7.2 常见错误六:聆听,而不是提供解决方案 20 2.8 现场调研...
  • 逻辑错误 1. 用try语句处理异常 异常捕获可以使用try语句来实现,任何出现在try语句范围内异常都会被及时捕获到 try语句种常见形式 try-except try-finally try块必须与except或finally块一起使用

    点击跳转
    《Python入门系列目录》



    • 程序的错误
      • 语法错误
      • 运行时错误
      • 逻辑错误

    1. 用try语句处理异常

    • 异常捕获可以使用try语句来实现,任何出现在try语句范围内的异常都会被及时捕获到
    • try语句的两种常见形式
      • try-except
      • try-finally
    • try块必须与except或finally块一起使用

    image

    1.1 try-except

    • 执行方式如下

      • 尝试执行try语句内可能出现问题的代码
      • 如果发现确实出现了我们所写的异常,则执行except部分的处理代码,然后正常执行后面的代码
      • 否则直接执行try语句中的代码段,然后正常执行后面的代码
      try:
          # 文件名为file1.txt,此处写成file.txt
          f = open("F:/file.txt", 'r')
      except FileNotFoundError:
          print('文件找不到!!')  # 文件找不到!!
      
      try:
          # 文件存在
          f = open("file1.txt", 'r')
          print(a)
      except FileNotFoundError:
          print("文件找不到!")
      except NameError:
          print("变量未定义!")  # 执行了这一条
      
    • 若无法确定要对哪一类异常做处理时,也可以写成如下形式

      ...
      except:
          print("出错了!")
      ...
      
    • 处理除数有0的异常

      try:
          s = input("请输入一个数学表达式:")
          print(eval(s))
      except ZeroDivisionError:
          print("除数不可以为0!")
      

    1.2 try-finally

    • 执行方式如下

      • 尝试执行try语句内可能出现问题的代码
      • 如果发现确实出现了我们所写的异常,则执行except部分的处理代码,然后必须执行finally部分的代码,再去执行后面其他的代码
      • 如果没有发现异常,则直接执行try语句中的代码段,跳过except部分,但仍要执行finally部分的代码,再去执行后面其他的代码
      • 一个try块后最多只能接一个finally块
      try:
          f = open("result.txt", 'r')  # 文件存在
          print(a)
      except NameError:
          print("变量未定义!")
      finally:
          f.close()
      
    • 对于try-finally模型来说,except语句部分是可有可无的,如果不写except语句部分,则如果发生异常,会输出Traceback信息,然后执行finally部分的语句

      try:
          f = open("result.txt",'r')
          print(a)
      finally:
          f.close()
      

    2. 常见的异常处理

    异常 描述
    NameError 尝试访问一个不存在的变量
    ZeroDivisionError 除数为0
    SyntaxError 语法错误
    IndexError 索引超出序列范围
    KeyError 请求一个不存在的字典关键字
    OSError 操作系统产生的错误,就像打开一个不存在的文件会引发FileNotFoundError,它是OSError的子类
    AttributeError 尝试访问未知的对象属性
    TypeError 不同类型间的无效操作,比如:1 + ‘1’

    3. 内置异常类

    image

    4. 捕获异常的顺序

    • except块可以捕获并处理特定的异常类型(此类型称为“异常筛选器”),具有不同异常筛选器的多个except块可以串联在一起
    a = (44, 78, 90, -80, 55)
    total = 0
    try:
        for i in a:
            if i < 0:
                raise ValueError(str(i) + "为负数")    # 自定义抛出异常
            total += i
        print('合计=', total)
    except Exception:       # 出现此异常。该异常是父类,且按except顺序捕获
        print('发生异常')
    except ValueError:
        print('数值不能为负')
    

    5. 自定义异常类

    • 自定义异常类一般继承于Exception或其子类
    • 自定义异常类的命名规则一般以Error或Exception为后缀
    class NumberError(Exception):  # 自定义异常类,继承于Exception
        def __init__(self, data):
            Exception.__init__(self, data)
            self.data = data
    
        def __str__(self):  # 重载str方法
            return self.data + ':非法数值(<0)'
    
    
    def total(data):
        total = 0
        for i in data:
            if i < 0:
                raise NumberError(str(i))
            total += i
        return total
    
    
    # 测试代码
    data1 = (44, 78, 90, 80, 55)
    print('总计=', total(data1))
    data2 = (44, 78, 90, -80, 55)
    print('总计=', total(data2))
    
    展开全文
  • 文章目录第一章:python之异常处理一、什么是异常二、为何要做异常处理三、异常的三个组成部分常见的错误类型针对逻辑上的异常又分成两处理方式1.错误发生的条件是可以预知的,使用if判断来解决2.错误发生的条件...

    第十一章:python之异常处理

    一、什么是异常

    异常: 程序发生错误的信号,程序一旦出错就会抛出异常,程序的运行也会随之终止,如下例子:

    print('start run...')
    (1,2,3,4,5)(99)
    print('stop run...')
    # TypeError: 'tuple' object is not callable
    

    二、为何要做异常处理

    # 为了增强程序的健壮性,即便是程序运行过程中出错了,也不要终止程序
    # 而是捕捉异常并处理:将出错信息记录到日志内
    

    三、异常的三个组成部分

    # 异常的追踪信息
    # 异常的类型
    # 异常的内容
    

    常见的错误类型

    # 4.1 语法错误:SyntaxError
    #     应该在程序运行前就改正
    # if 1>3
    #     print("run...")
    
    
    # 4.2 逻辑错误
    # number01
    age=input(">>: ").strip()
    if age.isdigit():
        age=int(age)
        print(age > 10)
        
    
    # number02
    print(x)
    # NameError: name 'x' is not defined
    
    
    # number03
    l=['a','b']
    l[2]
    
    # IndexError: list index out of range
    
    
    # number04
    class Foo:
        pass
    
    Foo.y
    
    # AttributeError: type object 'Foo' has no attribute 'y'
    
    

    针对逻辑上的异常又分成两种处理方式

    1.错误发生的条件是可以预知的,使用if判断来解决

    age=input('>>: ').strip() # 输入的只要不是数字就会出错
    if age.isdigit():
        age=int(age)
        if age > 18:
            print('猜大了')
        elif age < 18:
            print('猜大了')
        else:
            print('猜对了')
    else:
        print('必须输入数字')
    

    2.错误发生的条件是无法预知的

    print('start...')
    try:
        # 有可能会抛出异常的代码
        dic={'name':'wuchangwne'}
        dic['age']
        # 子代码1
        # 子代码2
        # 子代码3
    except IndexError as e:
        print('异常的信息: ', e)
    except NameError as e:
        print('异常的信息: ', e)
    
    else:
        print('如果被检测的子代码块没有异常发生,则会执行else的子代码')
    finally:
        print('无论被检测的子代码块有无异常发生,都会执行finally的子代码')
    
    
    print('end...')
    

    四、如何异常处理

    异常处理的语法

    '''
    
    
    try:
        代码1
        代码2
        代码3
    except 异常类型1 as e:
        处理异常的代码1
    except 异常类型2 as e:
        处理异常的代码2
    except (异常类型3,异常类型4,异常类型5) as e:
        处理异常的代码3
    except Exception as e:
        处理异常的代码4
    else:
        被监测的代码块没有发生异常时执行的代码
    finally:
        无论被监测的代码块有无异常都会执行该代码
    
    print('===>other code<====')
    '''
    
    # try不能单独和else连用,如果要用else,必须配合except
    """
    try:
        print(111)
        print(222)
        print(3333)
    except Exception:
        pass
    else:
        print('ok')
    print('===>other code<====')
    """
    
    print('start...')
    
    try:
        print('1111111111')
        print('2222222222')
        print('33333333')
        x
    except Exception as e:  # 万能异常
        print('所有异常都可以匹配的到')
    else:
        print('没有异常====>')
    
    print('end....')
    
    
    # 获取多个异常
    try:
        print('start...')
        l=[]
        l[100]
        print('end...')
    except KeyError as e:
        print("Key错误:",e)
    except IndexError as e:
        print("索引错误:",e)
    except Exception:
        pass
    print('===>other code<====')
    
    # finally可以单独与try配合使用
    try:
        执行sql1
        执行sql2
        执行sql3
        执行sql4
        执行sql5
    except Exception:
        执行回滚操作
    else:
        执行提交操作
    print('===>other code<====')
    
    # try:
    #     print(1111)
    #     sadf
    #     print(2222)
    #     print(33333)
    # finally:
    #     print('====>finally')
    #     # 回收资源
    

    断言

    '''
    # 上半部分
    print(111)
    print(222)
    print(333)
    names=['egon','jack',]
    
    # if len(names) != 3:
    #     raise Exception("数据错误")
    assert len(names) == 3
    
    # 下半部分
    print(names[2])
    '''
    

    raise主动抛出异常

    class NameType(BaseException):
        def __init__(self,msg):
            self.msg=msg
        def __str__(self):
            return "<%s>" %self.msg
    
    class People:
        def __init__(self,name):
            self.__name=name
    
        @property
        def name(self):
            return self.__name
    
        @name.setter
        def name(self,v):
            if not isinstance(v,str):
                raise NameType("名字必须是str类型")
            self.__name=v
    
        @name.deleter
        def name(self):
            del self.__name
    
    obj=People('egon')
    obj.name=123123
    
    class Animal:
        def speak(self):
            raise Exception("必须定义speak方法")
    
        def run(self):
            raise Exception("必须定义run方法")
    
    
    class Dog(Animal):
        pass
    
    class People(Animal):
        pass
    
    
    obj1=Dog()
    obj2=People()
    
    
    obj1.speak()
    # obj1.run()
    

    作者:吴常文
    出处:https://blog.csdn.net/qq_41405475
    本文版权归作者和CSDN共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

    展开全文
  • python异常处理

    2020-06-02 22:31:58
    在程序运行过程中,总会遇到各种各样的问题和错误。...异常有很多种类型,Python内置了几十种常见的异常,就在builtins模块内,无需特别导入,直接就可使用。需要注意的是,所有的异常都是异常类,首字
    • 异常处理

    在程序运行过程中,总会遇到各种各样的问题和错误。有些错误是我们编写代码时自己造成的,比如语法错误、调用错误,甚至逻辑错误。还有一些错误,则是不可预料的错误,但是完全有可能发生的,比如文件不存在、磁盘空间不足、网络堵塞、系统错误等等。这些导致程序在运行过程中出现异常中断和退出的错误,我们统称为异常。大多数的异常都不会被程序处理,而是以错误信息的形式展现出来。

    异常有很多种类型,Python内置了几十种常见的异常,就在builtins模块内,无需特别导入,直接就可使用。需要注意的是,所有的异常都是异常类,首字母是大写的!

    Python内置了一套try...except...finally(else)...的异常处理机制,来帮助我们进行异常处理。其基本语法是:

    try:
        pass
    except Exception as ex:        #as 表示取别名
        pass
    注:在Python3中,原来的Python2中的except Exception , ex的取别名方法已经不能使用。逗号,被认为是两种异常的分隔符,而不是取别名。

    Python的异常机制具有嵌套处理的能力,比如下面的函数f3()调用f2(),f2()调用f1(),虽然是在f1()出错了,但只需要在f3()进行异常捕获,不需要每一层都捕获异常。

    def f1():
        return 10/0
    
    def f2():
        f1()
    
    def f3():
        f2()
    
    f3()
    >>>
    Traceback (most recent call last):
      File "/Users/mlamp/Documents/py_project/parameter.py", line 87, in <module>
        f3()
      File "/Users/mlamp/Documents/py_project/parameter.py", line 86, in f3
        f2()
      File "/Users/mlamp/Documents/py_project/parameter.py", line 83, in f2
        f1()
      File "/Users/mlamp/Documents/py_project/parameter.py", line 81, in f1
        return 10/0
    ZeroDivisionError: division by zero
    
    ----------------------------------------
    
    try:
        f3()
    except ZeroDivisionError as e:        #as e 表示将ZeroDivisionError的详情赋值给 e,然后处理 e
        print(e)
    
    >>>
    division by zero

    try…except…语句处理异常的工作机制如下

    • 首先,执行try子句(在关键字try和关键字except之间的语句)
    • 如果没有异常发生,忽略except子句,try子句执行后结束。
    • 如果在执行try子句的过程中发生了异常,那么try子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的except子句将被执行。

    如果一个异常没有与任何的except匹配,那么这个异常将会传递给上层的try中。也就是前面说的嵌套处理能力。直到程序最顶端如果还没有被捕获,那么将弹出异常

    try:
        try:
            print("发生异常之前的语句正常执行")
            print(1/0)
            print("发生异常之后的语句不会被执行")
        except ValueError as e:
            print(e)
    
    except ZeroDivisionError as e:
        print(e)
        print("里层没有抓好,只能辛苦我外层了")
    >>>
    发生异常之前的语句正常执行
    division by zero
    里层没有抓好,只能辛苦我外层了

    可能包含多个except子句,分别来处理不同的特定的异常。但最多只有一个分支会被执行。所以except子句有排序先后问题,进了一条巷子就不会进别的巷子。

    try:
        print("发生异常之前的语句正常执行")
        print(1/0)
        print("发生异常之后的语句不会被执行")
    except NameError as e:
        print(e)
    except ZeroDivisionError as e:
        print("我是第一个抓取到除零异常的")
    except (ValueError,ZeroDivisionError) as e:
        print("我是备胎")
    
    >>>
    发生异常之前的语句正常执行
    我是第一个抓取到除零异常的

    通用异常 Exception

    在Python的异常中,有一个通用异常:Exception,它可以捕获任意异常

    s1 = 'hello'
    int(s1)
    >>>
    ValueError: invalid literal for int() with base 10: 'hello'
    ------------------------
    try:
        int(s1)
    except Exception as e:    #Exception异常会将所有的异常的详情赋值给e,然后处理 e
        print(e)
    
    >>>
    invalid literal for int() with base 10: 'hello'

    那么既然有这个什么都能管的异常,其他诸如OSError、ValueError的异常是不是就可以不需要了?当然不是!很多时候程序只会弹出那么几个异常,没有必要针对所有的异常进行捕获,那样的效率会很低。另外,根据不同的异常种类,制定不同的处理措施,用于准确判断错误类型,存储错误日志,都是非常有必要甚至强制的。

    finally和else子句

    try except语法还有一个可选的else子句,如果使用这个子句,那么必须放在所有的except子句之后。这个子句将在try子句没有发生任何异常的时候执行。当try子句发生异常以后,就不会执行else后面的子句

    同样的,还有一个可选的finally子句。无论try执行情况和except异常触发情况,finally子句都会被执行!

    try:
        print('try...')
        r = 10 / int('a')
        print('result:', r)
    except ValueError as e:
        print('ValueError:', e)
    finally:
        print('finally...')
    print('END')
    >>>
    try...
    ValueError: invalid literal for int() with base 10: 'a'
    finally...
    END
    

    当else和finally同时存在时:

    try:                #try后面没有异常发生
        pass        
    except:
        pass
    else:
        print("else")
    finally:
        print("finally")
    >>>
    else
    finally
    ------------------------------------------
    try:            #try 后面有异常发生
        1/0
    except:
        pass
    else:
        print("else")
    finally:
        print("finally")
    
    >>>
    finally

    主动抛出异常:raise

    很多时候,我们需要主动抛出一个异常。Python内置了一个关键字raise,可以主动触发异常

    >>> raise
    Traceback (most recent call last):
      File "<pyshell#0>", line 1, in <module>
        raise
    RuntimeError: No active exception to reraise
    >>> raise NameError("kkk")
    Traceback (most recent call last):
      File "<pyshell#1>", line 1, in <module>
        raise NameError("kkk")
    NameError: kkk

    raise唯一的一个参数指定了要被抛出的异常的实例,如果什么参数都不给,那么会默认抛出当前异常

    try:
        1/0
    except ZeroDivisionError as ex:
        print("记录异常日志: ", ex)
        print("但是我自己无法处理,只能继续抛出,看看上层能否处理(甩锅)")
        raise

    有时候,你需要主动弹出异常,作为警告或特殊处理:

    sex = int(input("Please input a number: "))
    
    try:
        if sex == 1:
            print("这是个男人!")
        elif sex == 0:
            print("这是个女人!")
        else:
            print("好像有什么不符合常理的事情发生了!!")
            raise ValueError("非法的输入")
    except ValueError:
        print("性别不明确!!!")

    更多的时候,你需要使用raise抛出你自定义的异常

    自定义异常

    Python内置了很多的异常类,并且这些类都是从BaseException类派生的。

    下面是一些常见异常类,请把它们记下来!这样你在见到大多数异常的时候都能快速准确的判断异常类型。

    异常名 解释
    AttributeError 试图访问一个对象没有的属性
    IOError 输入/输出异常
    ImportError 无法引入模块或包;多是路径问题或名称错误
    IndentationError 缩进错误
    IndexError 下标索引错误
    KeyError 试图访问不存在的键
    KeyboardInterrupt Ctrl+C被按下,键盘终止输入
    NameError 使用未定义的变量
    SyntaxError 语法错误
    TypeError 传入对象的类型与要求的不符合
    UnboundLocalError 试图访问一个还未被设置的局部变量
    ValueError 传入一个调用者不期望的值,即使值的类型是正确的
    OSError 操作系统执行错误

    大多数情况下,上面的内置异常已经够用了,但是有时候你还是需要自定义一些异常。自定义异常应该继承Exception类,直接继承或者间接继承都可以,例如:

    class MyExcept(Exception):
    
        def __init__(self, msg):
            self.message = msg
    
    try:
        raise MyExcept('我的异常!')
    except MyExcept as ex:
        print(ex)
    >>>
    我的异常
    • python 代码调试

    调试

    有的问题简单,有的问题很复杂,但不管简单还是复杂,通常我们都无法一眼就能看出问题的具体性质。我们需要知道出错时,哪些变量的值是正确的,哪些变量的值是错误的,某些关键的代码是否符合我们的预期,这些就需要我们将过程状态输出到屏幕或日志上,方便我们检查和分析。

    1. 初学者简单粗暴的方法:print大法

    print()方法是新手最常用的方法,也是比较简单的方法。但是,用print()最大的问题是将来还得删掉它,而且代码里多了很多无用的行,想想程序里到处都是print(),运行结果也会包含很多垃圾信息,还影响执行效率,代码一点也不简洁优雅,就觉得不是那么愉快了。

    2. 断言assert

    Python内置了一个assert关键字,表示断言。凡是用print()来辅助查看的地方,都可以用断言来替代。它会对后面的表达式进行判断,如果表达式为True,那就什么都不做,程序接着往下走;如果False,那么就会弹出异常

    assert是一个非常有用的技巧,通过选择关键因子,对因子的状态进行判定,可以将程序一块一块的进行划分,逐步的缩小问题范围。但是,程序中如果到处充斥着assert,和print()相比也好不到哪去。不过,启动Python解释器时可以用-O参数来关闭assert。关闭后,所有的assert语句相当于pass语句。

    3. 日志logging

    logging是Python内置的一个日志模块,不但可以将信息在屏幕上打印,还可以输出到文件,保留下来。使用logging之前,需要先通过import logging导入该模块

    logging允许你指定记录信息的级别,有DEBUG,INFO,WARNING,ERROR等几种级别,级别参数level会忽略比它低的级别信息。当指定level=INFO时,logging.DEBUG就不起作用了。同理,指定level=WARNING后,DEBUGINFO就不起作用了。logging.basicConfig(level=logging.INFO)这行就是指定只有INFO以上级别的信息才会被记录下来。

    4. Pycharm调试方法

    单元测试之unittest

    单元测试是用来对一个模块、一个函数或者一个类进行正确性检验的工作。你的代码可能在语法、词法和运行过程中没有问题了,但是并不能代表它就完全符合你的设计预期,很有可能你希望得到A,它给你的结果却是B。这就需要我们对程序进行单元测试。单元测试测的不是语法问题,而是业务逻辑是否正确的问题

    一旦编写好单元测试,我们就可以运行单元测试。最简单的运行方式是在代码的最后加上:

    if __name__ == '__main__':
        unittest.main()

    另一种方法是在命令行中通过参数-m unittest运行单元测试:

    $ python -m unittest 测试脚本
    • python 模块与包

    在编程语言中,代码块、函数、类、模块,一直到包,逐级封装,层层调用。在Python中,一个.py文件就是一个模块,模块是比类更高一级的封装。在其他语言,被导入的模块也通常称为库。

    模块可以分为自定义模块、内置模块和第三方模块

    为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package),包是模块的集合,比模块又高一级的封装。没有比包更高级别的封装,但是包可以嵌套包,就像文件目录一样,

    包名通常为全部小写,避免使用下划线

    在Python中,模块(包、类、函数)的导入方式有以下四种:

    • import xx.xx
    • from xx.xx import xx
    • from xx.xx import xx as rename    为了避免命名冲突,在导入的时候,可以给导入的对象重命名
    • from xx.xx import *         将对象内的所有内容全部导入。非常容易发生命名冲突,请慎用!

    默认情况下,模块的搜索顺序是这样的:

    1. 当前执行脚本所在目录
    2. Python的安装目录
    3. Python安装目录里的site-packages目录

    其实就是“自定义”——>“内置”——>“第三方”模块的查找顺序。任何一步查找到了,就会忽略后面的路径,所以模块的放置位置是有区别的。

    一般在pycharm中导入时出错,可以在命令行中执行,就可以找到错误的原因

    包(Package):

    只有包含__init__.py文件的目录才会被认作是一个包

    展开全文
  • excel使用

    2012-11-25 17:06:01
    (3)创建条件格式 可以使用六种逻辑符号来设计一个条件格式:>(大于)、>=(大于等于)、<(小于)、(小于等于)、=(等于)、(不等于),如果你觉得这些符号不好记,就干脆使用“>”或“>=”号来表示。...
  • 6.21

    2020-06-22 03:02:06
    面向对象的三大特点:封装、继承、多态 面向过程:根据业务逻辑从上到下写代码 ...2.异常有很多类型,Python 内置了几十种常见的异常,无需特别导入,直接就可以用。所有异常都是异常类,首字母是大写的。
  • 接下来介绍了许多巧妙的调试技术,并且通过真实的示例来展示各种常见的C#编程错误。 读者在《.NET高级调试》中可以学到: ●使用事后调试技术,包括Power DBG以及其他“强大的调试工具”。 ●理解在.NET CLR 4....
  • ● 处理错误条件异常机制。 ● 管理函数、类和变量名名称空间。 本书在传授知识方面有几个优点。大约20年前,《C Primer Plus))一书开创了优良初级教程传统,本书 建立在这样基础之上,吸收了其中很多...
  • ● 处理错误条件异常机制。 ● 管理函数、类和变量名名称空间。 本书在传授知识方面有几个优点。大约20年前,《C Primer Plus))一书开创了优良初级教程传统,本书 建立在这样基础之上,吸收了其中很多...
  • ● 处理错误条件异常机制。 ● 管理函数、类和变量名名称空间。 本书在传授知识方面有几个优点。大约20年前,《C Primer Plus))一书开创了优良初级教程传统,本书 建立在这样基础之上,吸收了其中很多...
  • ● 处理错误条件异常机制。 ● 管理函数、类和变量名名称空间。 本书在传授知识方面有几个优点。大约20年前,《C Primer Plus))一书开创了优良初级教程传统,本书 建立在这样基础之上,吸收了其中很多...
  • ASCII码 通常说二进制、进制和十六进制 一个字节有八位,最简单的ASCII...文本文件是基于字符编码的文件,常见的编码有ASCII编码,UNICODE编码等等 二进制文件是基于值编码的文件,你可以根据具体应用,指定某个值
  • ADO.NET 方案示例:提供数据识别应用程序的常见编程方案示例,并使用 ADO.NET 提供这些方案解决方案。 检索“标识”或“自动编号”值:提供一个特定示例,它将为 Microsoft SQL Server 表中“标识”(Identity) ...
  • JAVA面试题最全集

    2010-03-13 13:09:10
    找出下列代码可能存在的错误,并说明原因: 二、JSP&Servlet技术 1.描述JSP和Servlet区别、共同点、各自应用范围 2.在Web开发中需要处理HTML标记时,应做什么样处理,要筛选那些字符(< > & “”) 3.在...
  • 2.6.2 常见错误四:不注意收集异常事实,挖掘背后需求 18 2.7 现场调研阶段容易犯哪些错误?(三) 19 2.7.1 常见错误五:每天调研工作时间太长 19 2.7.2 常见错误六:聆听,而不是提供解决方案 20 2.8 现场调研...
  • C#微软培训教材(高清PDF)

    千次下载 热门讨论 2009-07-30 08:51:17
    7.5 逻辑操作符和逻辑表达式.68 7.6 位 运 算 .69 7.7 其它特殊操作符 .72 7.8 小 结 .77 第八章 流 程 控 制 .79 8.1 条 件 语 句 .79 8.2 循 环 语 句 .86 8.3 条 件 编 译.90 8.4 异常处理语句 ....
  • 业day19up 深度遍历与广度遍历正则表达式小结最简单递归递归顺序递归求和递归腾讯台阶面试题文件夹的函数遍历文件夹遍历文件夹有层次感栈模拟...模拟递归遍历文件夹层次感普及网站提取概念栈修改的逻辑错误广度遍历 ...
  • C#微软培训资料

    2014-01-22 14:10:17
    7.5 逻辑操作符和逻辑表达式.68 7.6 位 运 算 .69 7.7 其它特殊操作符 .72 7.8 小 结 .77 第八章 流 程 控 制 .79 8.1 条 件 语 句 .79 8.2 循 环 语 句 .86 8.3 条 件 编 译.90 8.4 异常处理语句 ....
  • 答: ● 软件是一种逻辑产品,具有无形性;  ● 软件产品生产主要是研制;  ● 软件不存在磨损和老化问题,但存在退化问题;  ● 软件产品生产主要是脑力劳动;  ● 软件产品成本非常昂贵,其开发...
  • 软件工程教程

    2012-07-06 23:10:29
    过去数十种面向对象建模语言各自为战,而UML可以消除一些潜在差异,一统江湖 通过统一语义和符号表示,提高面向对象技术 使项目建立在一个成熟标准建模语言基础之上 便于沟通和交流,统一理解 UML主要内容 ...
  • 书中内容主要集中在大多数企业常见的问题之上,如安装和升级到oracle database 11g数据库软件、创建数据库、导出和导入数据、数据库的备份与恢复、性能调优,等等。  本书还提供了dba完成本职工作必备的基本的uniix...
  • 2.4 目前市场上常见的轻量级J2EE开发容器 2.5 小结 第二篇 建立和使用J2EE的开发平台 第三章 建立Java的开发平台 3.1 建立Java的开发环境 3.1.1 下载JDK 3.1.2 安装JDK 3.1.3 设定Path、Classpath和JAVA_HOME 3.2 ...

空空如也

空空如也

1 2 3 4 5
收藏数 87
精华内容 34
关键字:

十种常见的逻辑错误