zoukankan      html  css  js  c++  java
  • 小白学习之路,面向对象补充

    一,异常处理

    终于到了在小白的路上经常遇到的东西了,异常我们非常的不陌生,因为在写程序的过程中,错误是经常会遇到的,特别是刚刚学习的小白。今天我们就来了解一下异常到底是一个什么东西,是怎么玩的。

    首先先介绍一下有哪些我们常见的异常跟表示什么错误吧。

     1 AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
     2 IOError 输入/输出异常;基本上是无法打开文件
     3 ImportError 无法引入模块或包;基本上是路径问题或名称错误
     4 IndentationError 语法错误(的子类) ;代码没有正确对齐
     5 IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
     6 KeyError 试图访问字典里不存在的键
     7 KeyboardInterrupt Ctrl+C被按下
     8 NameError 使用一个还未被赋予对象的变量
     9 SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
    10 TypeError 传入对象类型与要求的不符合
    11 UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
    12 导致你以为正在访问它
    13 ValueError 传入一个调用者不期望的值,即使值的类型是正确的

    当然还有很多其他的异常

     1 ArithmeticError
     2 AssertionError
     3 AttributeError
     4 BaseException
     5 BufferError
     6 BytesWarning
     7 DeprecationWarning
     8 EnvironmentError
     9 EOFError
    10 Exception
    11 FloatingPointError
    12 FutureWarning
    13 GeneratorExit
    14 ImportError
    15 ImportWarning
    16 IndentationError
    17 IndexError
    18 IOError
    19 KeyboardInterrupt
    20 KeyError
    21 LookupError
    22 MemoryError
    23 NameError
    24 NotImplementedError
    25 OSError
    26 OverflowError
    27 PendingDeprecationWarning
    28 ReferenceError
    29 RuntimeError
    30 RuntimeWarning
    31 StandardError
    32 StopIteration
    33 SyntaxError
    34 SyntaxWarning
    35 SystemError
    36 SystemExit
    37 TabError
    38 TypeError
    39 UnboundLocalError
    40 UnicodeDecodeError
    41 UnicodeEncodeError
    42 UnicodeError
    43 UnicodeTranslateError
    44 UnicodeWarning
    45 UserWarning
    46 ValueError
    47 Warning
    48 ZeroDivisionError

    下面介绍一下异常处理的简单用法

    1 a=[2]
    2 try: #只能抓住一个异常
    3     print(a[3])
    4 except IndexError as e: #IndexError抓住异常,内容为e
    5     print('列表内容不存在',e)

    执行结果:列表内容不存在 list index out of range

    当然这里只有一个异常,如果有很多个异常是不是应该都要写出来呢,还有就是异常处理完以后应该怎么执行呢。当然异常也不仅仅只有这一点,下面是异常的进一步使用。

     1 a=[2]
     2 b={}
     3 try: #只能抓住一个异常
     4     print(a[3])
     5     b["name"]
     6 except IndexError as e: #IndexError抓住异常,内容为e
     7     print('列表内容不存在',e)
     8 except KeyError as e:
     9     print('输入的key不存在',e)
    10 except Exception as e:#Exception万能异常,能够抓住所有的异常
    11     print('出错了',e)
    12 else: #当没有错误发生,就执行else
    13     print('全部正常')
    14 finally: #不管是发生了异常还是程序没有出错都要执行
    15     print('最后都要执行')
    16 #执行结果:
    17 #列表内容不存在 list index out of range
    18 #最后都要执行
    View Code

    所以异常的总的结构如下

    1 try:
    2     # 主代码块
    3 except Exception as e:
    4     # 异常时,执行该块
    5 else:
    6     # 主代码块执行完,执行该块
    7 finally:
    8     # 无论异常与否,最终执行该块

    异常也是能主动触发的。

    1 try:
    2     raise Exception('错了错了') #主动触发异常,里面为异常内容
    3 except Exception as e:
    4     print(e)
    5 #执行结果:错了错了

    还有可以自己定义的自定义异常(可以用来装逼l)

    1 class Zzqexcept(Exception): #必须继承Exception这个基类
    2     def __init__(self,msg):
    3         self.msg=msg
    4 try:
    5     raise Zzqexcept('卧槽,网站有毒')#抛出这个异常
    6 except Zzqexcept as e:
    7     print('自定义异常:',e)

    在异常这里还有一个小东西,补充的那就是断言,什么是断言呢,如果在执行过程中,断言里面的内容有错,就会直接让程序报错。如果没错程序继续执行。

    assert 'z' in 'zzq' #错误的话直接让程序报错,后面是条件

    二,接口类和抽象类

    在工作中,可能会存在一些这样的需求。比如你在公司,要求必须代码规范化。在实现一个支付功能的时候,可能会有微信支付,支付宝支付等不同情况,然后呢,又是不同的人来写。有的人英语水平好一点的可能会用pay作为方法名,但是有的人会用cost啊等等不同情况。所以公司为了方便管理这种情况,就会使用到接口类或者是抽象类。如果在接口类中定义了一个方法,那么在继承他的子类里面必须使用它的这个方法,如果没有使用,那么就会报错。

    接口类python原生是不支持的,支持抽象类。理论上可以继承多个接口类,但是抽象类只能继承一个。他们的本质其实是一样的。

    面向对象的开发规范 所有的接口类和抽象类都不能实例化。python中没有接口类,python中自带多继承 所以我们直接用class来实现了接口类,python中支持抽象类  : 一般情况下 单继承  不能实例化

     1 from abc import ABCMeta,abstractmethod
     2 class payment(metaclass=ABCMeta): #作为接口类
     3     @abstractmethod
     4     def pay(self,money):#在子类中必须执行的方法
     5         pass
     6 class weixin(payment):
     7     def pay(self,money):
     8         print('weixin pay %s'%money)
     9 class zhifubao(payment):
    10     def zhipay(self,money):
    11         print('zhifubao pay %s' %money)
    12 w=weixin()
    13 z=zhifubao()
    14 w.pay(100)
    15 z.zhipay(100)
    View Code

    执行结果:

    因为在后面那个类中,没有实现接口类中的方法,所以报了下面的错。

    当然,也是可以继承多个接口类的,比如动物,一个会飞会跑,一个会跑会游。我们就可以写三个不同的接口类,跑,游,走,然后根据自己的功能继承对应功能的接口类就行,使用方法跟单继承是一样的,下面就不写了。

    三,单例模式

    在很多时候,一个只需要一个对象就够了。比如在连接数据库的时候,一个对象就够了,如果实例化很多对象就会很浪费内存,所以就引入了单例模式。单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。

    单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。

    在 Python 中,我们可以用多种方法来实现单例模式:

    • 使用模块
    • 使用 __new__
    • 使用装饰器(decorator)
    • 使用元类(metaclass)

    1,使用模块

    模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。

    我们想要实现可以在test.py中新建类

    1 class Myclass(object):
    2     def say(self):
    3         print('hello world')
    4 t=Myclass()

    实现单例模式,在另一个py文件导入这个test.py文件

    1 from .test import t
    2 t.say()

    2,使用 __new__

    在使用之前让我们先来了解一下他到底是一个什么骚操作。如果我们仔细的去研究类的执行顺序的时候会发现,其实在__init__实例化之前,已经调用了__new__方法。__new__()必须要有返回值,返回实例化出来的实例。__init__()有一个参数self,该self参数就是__new__()返回的实例,__init__()在__new__()的基础上可以完成一些其它初始化的动作,__init__()不需要返回值。

     1 class Myclass(object):
     2     _instance = None
     3     def __new__(cls, *args, **kwargs):
     4         if not cls._instance:#没有实例化过
     5             # 继承原生的new方法,实例化一个对象
     6             cls._instance = super(Myclass, cls).__new__(cls, *args, **kwargs)
     7         return cls._instance#返回这一个对象
     8     def say(self):
     9         print('hello world')
    10 t=Myclass()
    11 t2=Myclass()
    12 print(id(t))#id() 函数用于获取对象的内存地址
    13 print(id(t2))
    View Code

    最后执行结果显示两个类实例化的对象是一个,实现了单例模式。

    当然,还有其他写法来实现,你只要读一下源码,了解了过程,就很好实现了。

    3,使用装饰器(decorator)

    前面我们讲过装饰器,当然这里也可以通过装饰器来实现单例模式。

     1 def singleton(cls):
     2     instances = {}
     3     def _singleton(*args,**kwargs):
     4         if cls not in instances:
     5             instances[cls] = cls(*args, **kwargs)
     6         return instances[cls]
     7     return _singleton
     8 @singleton
     9 class Test(object):
    10     def say(self):
    11         print('this is test')
    12 a=Test()
    13 b=Test()
    14 print(id(a),id(b))
    15 #执行结果:1888446950816 1888446950816
    View Code

    4,使用元类(metaclass)

    在使用之前,应该了解一下元类。

    元类(metaclass)可以控制类的创建过程,它主要做三件事:拦截类的创建,修改类的定义,返回修改后的类。

    具体介绍可以参考http://blog.jobbole.com/21351/

     1 #元类实现
     2 class Singleton(type):
     3     _instances = {}
     4     def __call__(cls, *args, **kwargs):
     5         if cls not in cls._instances:
     6             cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
     7         return cls._instances[cls]
     8 class test(metaclass=Singleton):
     9     def say(self):
    10         print('hello')
    11 t1=test()
    12 t2=test()
    13 print(id(t1),id(t2))
    14 #执行结果:2423941112328 2423941112328
    View Code

    讲了这几中实现单例模式的方法,当然你都可以选择使用。我个人比较喜欢用new方法实现。单例模式当然有好有坏,在正确的情况下使用,能够达到减小内存的使用的好处,如果使用不当,也可能会让程序报错。

  • 相关阅读:
    2016.7.22.noip2012D2
    2016.7.21.noip2014D2
    LIS最长上升子序列O(n^2)与O(nlogn)的算法
    vijos1910解方程
    vijos1909寻找道路
    viojs1908无线网路发射器选址
    P1907飞扬的小鸟
    P1906联合权值
    P1905生活大爆炸版 石头剪刀布
    poj1274(匈牙利算法)
  • 原文地址:https://www.cnblogs.com/zzqit/p/9216835.html
Copyright © 2011-2022 走看看