Python 之 面向对象编程

一、概述

1.1 与面向过程的对比

1.1.1 面向过程

  1. 概念:核心是“过程”二字,就是将你所需要开发的事物按照过程来编写,就像流水线一般,将每一项工艺怎么弄的定义成一个函数,就是面向过程编程。
  2. 优点:将一些大问题化成一系列小问题,将其简单化。
  3. 缺点:可拓展性差,即其只能用于特定的场合。
  4. 适用场景:用于不会常改变的场合,著名的例子有Linux內核,git,以及Apache HTTP Server等。

1.1.2 面向对象

  1. 概念:核心是“对象”二字,将过程所对应的函数统一成对象,在python,万物皆对象。
  2. 优点:可拓展性好。
  3. 缺点:编程的复杂度远高于面向过程。
  4. 适用场景:应用于需求经常变化的软件,集中在用户层,互联网应用,企业内部软件,游戏等。

二、类与对象

2.1 类

  1. 概念:就是一系列对象相似的特征与技能的结合
    1. 查看类的名称空间:
      1.   类名.__dict__  :     以字典的形式保存的
    1. 四个针对类的属性方法的操作(增删改查)
      1.   增:类名.属性名=值                    如Foo.name=‘jiangnan’
      2.         删:del   类名.属性名                 如 del   Foo.school
      3.        改:类名.属性名=修改后的值      如Foo.school=‘jiangnan’
      4.        查:类名.属性名                          如Foo.school

2.2 对象

  1. 创建的格式:对象名=类名(独有的属性(即__init__(属性名)))
  2. 在类中的函数属性是绑定给对象使用的,绑定不同的对象就有不同的绑定方法,对象调用方法时,会将对象本身作为第一个传入,即作为self传入。

 三、三大特性

面向对象的三大特性是指:继承、多态和封装。

3.1 继承

继承指的是类与类之间的关系,一个类可以继承一个或多个类,父类可以成为基类或超类。

3.1.1 查看继承

      语法:类名.__bases__

3.1.2 属性查找:

    先在自己类中查找,没有去父类中查找,以此类推。

      

3.1.3  继承实现的原理

    合并所有父类的mro列表(类名.__mro__)并遵循如下三条准则:

  •   子类会先于父类被检测
  •        多个父类会根据他们在列表中顺序被检查
  •        如果对下一个类存在两个合法的选择,选择第一个父类

  在python2中,有两种类:

    •   新式类:继承object的类,以及他的子类
    •        经典类:没有继承object的类,以及他的子类

  在python3中,只有新式类

  查找有两个方式:深度优先(新式类)、广度优先(经典类)
           经典类                          新式类(python3)

    

在子类中重调父类中的属性,有两种方法:

  • 指名道姓的使用(不依赖继承):父类名.属性名()
  • 使用super:super().属性名()
    简而言之,super()就是mro列表下一个查找的(广度优先)

3.1.4.  super原理

1 def super(cls,inst):
2     mro = inst.__class__.mro()
3     return mro[mro.index(cls)+1]

 

  其中,cls代表类,inst代表实例,上面的代码做了两件事:

  •  获取inst的mro列表
  •     查找cls在当前mro列表中的index,并返回它的下一个类,即mro[index+1]
    当你使用super(cls,inst)时,python会在inst的mro列表中搜索cls的下一个类

   现在举出一个例子:

class Base(object):
    def __init__(self):
        print("enter Base")
        print("leave Base")

class A(Base):
    def __init__(self):
        print("enter A")
        super(A, self).__init__()
        print("leave A")

class B(Base):
    def __init__(self):
        print("enter B")
        super(B, self).__init__()
        print("leave B")

class C(A, B):
    def __init__(self):
        print("enter C")
        super(C, self).__init__()
        print("leave C")

c=C()
print(C.__mro__)
View Code

 

 对于这类问题,我们先要知晓其mro列表中的顺序,对于本例子,mro列表:C-->A-->B-->object

因此,执行这个程序时,先执行的是C类,即先打印:enter C  ,然后遇到super,即在mro中进入下一个类中,即A,此刻在打印出  enter B,此后因此打印。当打印到object类时,最后反向返回,此处类似于递归。

此处答案应为:

enter C
enter A
enter B
enter Base
leave Base
leave B
leave A
leave C

 

3.1.5  组合

  1. 定义
    就是在一个类中以另外一个类的对象作为数据属性。即“什么”有“什么”
  2. 列子
    class Person:
        school='luffycity'
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
    class Teacher(Person):
        def __init__(self,name,age,sex,level,salary):
            super().__init__(name,age,sex)
            self.level=level
            self.salary=salary
        def teach(self):
            print('%s is teaching'%self.name)
    
    
    class Student(Person):
        def __init__(self,name,age,sex,class_time):
            super().__init__(name, age, sex)
            self.class_time=class_time
        def learn(self):
            print('%s is learning'%self.name)
    
    class Course:
        def __init__(self,course_name,course_price,course_period):
            self.course_name=course_name
            self.course_price=course_price
            self.course_period=course_period
    
        def tell_info(self):
            print('课程名<%s>课程价钱<%s>课程周期<%s>'%(self.course_name,self.course_price,self.course_period))
    View Code
    t1=Teacher('alex',18,'male',10,3000)
    python=Course('python',3000,'3mons')
    t1.course=python
    print(t1.course.course_name)#python
    t1.course.tell_info()#课程名<python>课程价钱<3000>课程周期<3mons>

    3. 当类之间有显著不同时,并且较小的类是较大的类所需要的组件时,使用组合

3.1.6 抽象类(了解)

  1. 定义
    与java一样,python也有抽象类的概念,但是同样需要借助模块实现,抽象类是一个特殊的类,他的特殊之处在于只能被继承,不能被实例化。
  2. 原因
    抽象类是从一堆类中抽象出来的,内容包括数据属性和函数属性。
    import abc
    
    class Animals(metaclass=abc.ABCMeta):#抽象类,只能被继承,不能被实例化
        all_type='animals'
        @abc.abstractmethod
        def run(self):
            pass
        @abc.abstractmethod
        def eat(self):
            pass
    
    class People(Animals):
        def run(self):
            print('1')
    
        def eat(self):
            print('e1')
    
    class dog(Animals):
        def run(self):
            print('2')
    
        def eat(self):
            print('e2')
    
    p1=People()
    p1.run()
    View Code 

 3.2 多态

  1. 定义
    就是指一类事物有多种形态,如:
    动物有多种形态:人、狗等都有走路说话吃饭等
    因此,多态就是指不考虑实例类型的情况下使用实例。
  2. abc模块的作用
    Python本身不提供抽象类和接口机制,要想实现抽象类,可以借助abc模块。ABC是Abstract Base Class的缩写。
  3. abc模块中的类和函数
    abc.ABCMeta
    这是用来生成抽象基础类的元类。由它生成的类可以被直接继承。
    abc.abstractmethod(function)
  4. 实例
    #多态:同一种类型的多种形态
    import abc
    class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
        @abc.abstractmethod
        def talk(self):
            print('haha')
    
    class People(Animal): #动物的形态之一:人
        def talk(self):
            print('say hello')
    
    class Dog(Animal): #动物的形态之二:狗
        def talk(self):
            super().talk()
    
    class Pig(Animal): #动物的形态之三:猪
        def talk(self):
            print('say aoao')

     调用时:

    #多态性:在不考虑实例类型的情况下使用实例
    peo1=People()
    dog1=Dog()
    pig1=Pig()
    
    peo1.talk()#say hello
    dog1.talk()#haha
    pig1.talk()#say aoao

    我们可以定义一个统一的接口来完成

    def func(animal):
        animal.talk()
    
    func(peo1)#say hello
    
    

     

 3.3 封装

 3.3.1 隐藏

class A:
    __x=1#_A__x=1

    def __init__(self,name):
        self.__name=name#self._A__name=name

    def __foo(self):#_A__foo(self)
        print('run foo')

    def bar(self):
        self.__foo()#self._A__foo()
        print('from bar')
   
  def ww(self):
      print(self.__x)
a=A('wei')##{'_A__name': 'wei'}
print(a.__dict__)##'__module__': '__main__', '_A__x': 1, '__init__': <function A.__init__ at 0x000001D26C0BB950>, '_A__foo': <function A.__foo at 0x000001D26C0BB9D8>, 'bar': <function A.bar at 0x000001D26C0BBA60>, '__dict__':。。。}
print(A.__dict__)##1
print(a._A__x)##run foo
a.bar()##from bar
a.ww()##1
View Code

 

 特点:

1、在类外部无法直接obj.__AttrName访问
2、在类内部可以直接obj.__AttrName访问
3、子类无法覆盖父类__开头的属性
如:
###常规
class A:
    def fa(self):
        print('from A')
    def test(self):
        self.fa()

class B(A):
    def fa(self):
        print('from B')
b=B()
b.test()

###结果:from B——————》覆盖了,调用的是自己类中的

#使用隐藏方式
class A:
    def __fa(self):#_A__fa
        print('from A')
    def test(self):
        self.__fa()#self._A__fa

class B(A):
    def __fa(self):#_B__fa
        print('from B')
b=B()
b.test()

###结果:from A ——————》没有覆盖,调用的还是父类的
View Code

 

 3.3.2 封装

  1. 封装数据属性:明确区分内外,控制外部对隐藏属性的操作行为
    class People:
        def __init__(self,name,age):
            self.__name=name
            self.__age=age
    
        def tell_info(self):
            print('name:%s;age:%s'%(self.__name,self.__age))
    
        def set_info(self,name,age):
            if not isinstance(name,str):
                print('名字必须是字符串')
                return
            if not isinstance(age,int):
                print('年龄必须是数字类型')
                return
            self.__name=name
            self.__age=age
    
    p=People('zhangsan',18)
    p.tell_info()
    p.set_info('alex','20')
    p.tell_info()
    p.set_info('alex1',30)
    p.tell_info()
    View Code

      输出的结果为:

    name:zhangsan;age:18
    年龄必须是数字类型
    name:zhangsan;age:18
    name:alex1;age:30
  2. 封装方法:为了隔离复杂度,即只显示我们的功能,而隐藏取得该功能的函数
    #取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
    #对使用者来说,只需要知道取款这个功能即可,其余功能都可以隐藏起来,很明显这么做,隔离了复杂度,同时也提升了安全性
    class ATM:
        def __card(self):
            print('插卡')
        def __auth(self):
            print('用户认证')
        def __input(self):
            print('输入取款金额')
        def __print_bill(self):
            print('打印账单')
        def __take_money(self):
            print('取款')
    
        def withdraw(self):
            self.__card()
            self.__auth()
            self.__input()
            self.__print_bill()
            self.__take_money()
    
    a=ATM()
    a.withdraw()
    View Code

四、反射

  定义:通过字符串映射到对象的属性

  python中反射功能有4个内置函数提供:hasattr、getattr、setattr、delattr,对应的含义为:检测是否含有某属性、获取该属性、设置属性、删除属性

  1.   hasattr(object,name)
    含义:通过字符串的形式去某个模块中判断东西是否存在
    具体:判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True,否则返回False。
  2.        getattr(object,name[,default])
    含义:通过字符串的形式去某个模块中获取东西
    具体:获取对象object的属性或者方法,如果存在,打印出来,如果不存在,打印出默认值
         注:如果返回的对象的方法,返回的是方法的内存地址,如果需要运行这个方法,在后面加个括号。
  3.       setattr(object,name,values)
    含义:通过字符串的形式去某个模块中设置东西
    具体:给对象的属性赋值,若属性不存在,先创建再赋值
  4.       delattr(object,name)
    含义:通过字符串的形式去某个模块中删除东西
    具体:删除属性

  例子:

class People:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def talk(self):
        print('%s is talking'%self.name)

p=People('alex',18,'male')

#检测是否含有某属性
print(hasattr(p,'name'))#-------------->True
#获取属性
print(getattr(p,'name'))#-------------->alex
#设置属性
print(setattr(p,'sex','flmale'))#-------------->None
print(p.sex)#-------------->flmale
#删除属性
print(p.__dict__)#-------------->{'name': 'alex', 'age': 18, 'sex': 'flmale'}
delattr(p,'name')#-------------->
print(p.__dict__)#-------------->{'age': 18, 'sex': 'flmale'}
View Code

   反射一般用于:在类中,通过输入的字符串来调用类中不同属性或者方法,如下面这个例子:

class Service:
    def run(self):
        while True:
            inp=input('>>: ').strip() #cmd='get a.txt'
            cmds=inp.split() #cmds=['get','a.txt']
            if hasattr(self,cmds[0]):
                func=getattr(self,cmds[0])
                func(cmds)

    def get(self,cmds):
        print('get.......',cmds)

    def put(self,cmds):
        print('put.......',cmds)

obj=Service()
obj.run()
View Code

  结果为:get....... ['get', 'a.txt'] 

 五、绑定方法与非绑定方法

在类内部定义方法,主要分为两类:绑定方法和非绑定方法

5.1 绑定方法

  1.   定义:
    绑定给谁就应该由谁来调用,谁来调用就会把调用者当做第一个参数自动传入

  2.        分类:
    主要分为两类:
    绑定到对象的方法:在类定义中没有被任何修饰器修饰的方法
    绑定到类的方法:在类定义中被classmethod修饰的方法

5.2 非绑定方法

  1.   定义:
    没有自动传值这么一说,就类中定义的一个普通函数,对象和类都可以使用,不与类对象绑定。

5.3 实例

class Foo:
    def __init__(self,name):
        self.name=name

    def tell(self):#绑定到对象的方法
        print('名字是%s' %self.name)

    @classmethod
    def func(cls): #绑定到类的方法#cls=Foo
        print(cls)

    @staticmethod
    def func1(x,y):#非绑定方法
        print(x+y)

f=Foo('alex')
print(Foo.tell)#<function Foo.tell at 0x000002A70F4AB9D8>
print(f.tell)#<bound method Foo.tell of <__main__.Foo object at 0x0000013C295F0518>>
print(Foo.func)#<bound method Foo.func of <class '__main__.Foo'>>
print(f.func)#<bound method Foo.func of <class '__main__.Foo'>>
print(Foo.func1)#<function Foo.func1 at 0x0000029E1342BAE8>
print(f.func1)#<function Foo.func1 at 0x0000029E1342BAE8>
View Code

 

 六、属性方法

属性方法就是通过@property把一个方法变成一个静态属性

 1 class People:
 2     def __init__(self,name,weight,height):
 3         self.name=name
 4         self.weight=weight
 5         self.height=height
 6     @property
 7     def bmi(self):
 8         print(self.weight / (self.height ** 2))
 9 
10 p=People('weimin',63.5,1.70)
View Code

 

 当调用时,使用

p.bmi()

 

就会报错,报错如下

1 Traceback (most recent call last):
2   File "C:/Users/。。。/Desktop/python/oldboypython/day5/19property.py", line 27, in <module>
3     p.bmi()
4 TypeError: 'float' object is not callable

 

因此,正确调用就是不加括号,就行静态属性一样调用即可。

p.bmi

 

那么把一个方法变成静态属性有什么作用呢?当客户需要对一个参数进行修改时,我们可以限制该参数的格式等,调用@property.setter来进行设置参数的值,@property.deleter进行删除,例子如下:

 1 class People:
 2     def __init__(self,name):
 3         self.__name=name
 4 
 5     @property
 6     def name(self):
 7         print('getter')
 8         return self.__name
 9 
10     @name.setter
11     def name(self,val):
12         print('setter',val)
13         if not isinstance(val,str):
14             print('名字必须是字符串类型')
15             return
16         self.__name=val
17 
18     @name.deleter
19     def name(self):
20         print('deleter')
21         print('不允许删除')
22 
23 p=People('alex')
24 p.name="ALEX"######------->  setter ALEX
25 p.name=123#######------->   setter 123;名字必须是字符串类型
26 del p.name######------->   deleter;不允许删除
View Code

 

 

 七、内置函数

在这里要注意的是,内置函数与私有成员是有区别的,内置函数是前后都有两个字符的下划线,而私有成员只有前两个字符是下划线,

且私有成员与公有成员的不同点在于:

  • 私有成员只能在类中调用,当然也可以在类外调用,格式为对象.__类__属性名
  • 公有成员在任何地方均可访问

内置函数:

 1、item系列(__getitem__/__setitem__/__delitem__)

  其实就是在类中,将之前用调用方法的方式变成调用字典的方式。上述的三个函数分别表示为:获取、设置、删除数据。

 1 class Foo: #Dict
 2     def __init__(self,name):
 3         self.name=name
 4 
 5     def __getitem__(self, item): #item='namexxx'
 6         print('getitem...',item)
 7         return self.__dict__.get(item)#返回value
 8 
 9     def __setitem__(self, key, value):
10         print('setitem...',key,value)
11         self.__dict__[key]=value#设置了key-value
12 
13     def __delitem__(self, key):
14         print('delitem...',key)
15         del self.__dict__[key]
16 
17 obj=Foo('egon')
18 #获取属性
19 print(obj['name'])#相当于print(obj.name)------->egon
20 #设置属性
21 obj['sex']='male'#调用__setitem__(self, key, value)函数
22 print(obj.__dict__)#------->{'name': 'egon', 'sex': 'male'}
23 #删除属性
24 del obj['sex']#调用__delitem__(self, key)函数,
25 print(obj.__dict__)#------->{'name': 'egon'}
item系列

  2、__init__、__call__、__new__

对于__init__:通过类创建对象之后,自动触发执行。

对于__call__:对象后面加括号,触发执行

 1 class Foo:
 2 
 3     def __init__(self):
 4         print('__init__')
 5 
 6     def __call__(self, *args, **kwargs):
 7         print('__call__')
 8 
 9 obj = Foo() # 执行 __init__------>__init__
10 obj()       # 执行 __call__------>__call__
__call__

 对于__new__:创建这个类对象的时候执行。

3、 __doc__

 查看类的描述信息。

1 class Foo:
2     '''描述类信息,看看'''
3      def __init__(self):
4          print('__init__')
5      def __call__(self, *args, **kwargs):
6          print('__call__')
7 
8 print(Foo.__doc__)#-------->'描述类信息,看看'        
View Code

 4、 __module__、__class__

 __module__   表示当前操作的对象在哪个模块

__class__       表示当前操作的对象的类是什么

1 class C:
2     def __init__(self):
3         self.name='xiaozhupeiqi'
CC
1 import os,sys
2 sys.path.append(os.path.dirname(__file__))
3 import CC
4 obj=CC.C()
5 print(obj.__module__)#------->CC
6 print(obj.__class__)#-------><class 'CC.C'>
CC2

 5、__str__、__repr__

改变对象的字符串显示__str__,__repr__

__str__ \__repr__ :在打印对象的时候执行,将返回的结果转成字符串格式打印出来

 1 class People:
 2     def __init__(self,name,age):
 3         self.name=name
 4         self.age=age
 5 
 6     def __str__(self):
 7         return 'Info(%s,%s)' % (self.name, self.age)
 8 
 9 obj=People('zhu',18)
10 print(obj)
__str__

 6、__del__

析构方法时,当对象在内存中被释放时,自动触发执行。在python中一般不需要定义。

比如:

f=open()-------->包括两部分:应用程序、操作系统(打开文件)

f.close()--------->回收操作系统的资源

但此时,f并没有被回收

7、isinstance(obj,cls)、issubclass(sub,super)

isinstance(obj,cls)判断是否obj是否是类cls的对象

1 class Foo(object):
2     pass
3 obj = Foo()
4 isinstance(obj, Foo)#------>True
isinstance

 

issubclass(sub,super)判断类sub是否是类super的子类

1 class Foo(object):
2     pass
3 class Bar(Foo):
4     pass
5 issubclass(Bar, Foo)#------->True
issubclass

 

八、元类

之前,我们一直说,python中一切皆对象,因此,类也是对象,因此,类的类型为type,称为type。

当使用type创建类的时候,有以下形式:

type(类名,父类的元组(可以为空),属性的字典)

例子:

1 def  printInfo(self):
2      print("%s is %d years old" %(self.name, self.age))
3 
4 S = type("Student", (object, ), {"name": "Wilber", "age": 28, "printStudentInfo": printInfo})
5 
6 print(type(S))#-------->type
7 s=S()
8 print(type(s))#--------->Student
9 s.printStudentInfo()#--->Wilber is 28 years old
type创建类

 

当需要自定义一个类时,我们可以设置"metaclass"属性。

就是,先定义metaclass,就可以创建类,最后创建实例。

例子:

 1 class ListMetaclass(type):
 2     def __new__(cls, name, bases, attrs):
 3         attrs['add'] = lambda self, value: self.append(value)
 4         return type.__new__(cls, name, bases, attrs)
 5 
 6 class MyList(list, metaclass=ListMetaclass):
 7     pass
 8 
 9 L = MyList()
10 L.add(1)
11 print(L)#------>[1]

当我们传入关键字参数metaclass时,它指示Python解释器在创建MyList时,要通过ListMetaclass.__new__()来创建,在此,我们可以修改类的定义,比如,加上新的方法,然后,返回修改后的定义。

 1 class Mymeta(type):
 2     def __init__(self,class_name,class_bases,class_dir):
 3         if not class_name.istitle():
 4             raise TypeError('类名的首字母必须大写')
 5 
 6         if '__doc__' not in class_dir or not class_dir['__doc__'].strip():
 7             raise TypeError('必须有注释,且注释不能为空')
 8         super().__init__(class_name,class_bases,class_dir)
 9 
10 class Chinese(object,metaclass=Mymeta):#Chinese=type(...)
11     '''
12     中国人的类
13     '''
14     country='China'
15     def __init__(self,name,age):
16         self.name=name
17         self.age=age
18 
19     def talk(self):
20         print('%s is talking'%self.name)
21 
22 
23 # Chinese=Mymeta(class_name,class_bases,class_dir)
24 
25 print(Chinese.__dict__)#---->{'__module__': '__main__', '__doc__': '\n    中国人的类\n    ', 'country': 'China', '__init__': <function Chinese.__init__ at 0x0000022F8BE8A9D8>, 'talk': <function Chinese.talk at 0x0000022F8BE8AA60>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>}
26 c=Chinese('xiaoming',18)
自定义元类控制类的创建行为
 1 class Mymeta(type):
 2     def __init__(self,class_name,class_bases,class_dir):
 3         if not class_name.istitle():
 4             raise TypeError('类名的首字母必须大写')
 5 
 6         if '__doc__' not in class_dir or not class_dir['__doc__'].strip():
 7             raise TypeError('必须有注释,且注释不能为空')
 8         super().__init__(class_name,class_bases,class_dir)
 9 
10     def __call__(self, *args, **kwargs):#obj=Chinese('alex',age=18),self=Chinese,args=('alex',),kwargs={'age': 18}
11         obj=object.__new__(self)#第一件事:先造出一个空对象
12         self.__init__(obj,*args, **kwargs)#第二件事:初始化obj
13         return obj#第三件事:返回obj
14 
15 class Chinese(metaclass=Mymeta):#Chinese=type(...)
16     '''
17     中国人的类
18     '''
19     country='China'
20     def __init__(self,name,age):
21         self.name=name
22         self.age=age
23 
24     def talk(self):
25         print('%s is talking'%self.name)
26 
27 obj=Chinese('alex',age=18)
28 print(obj.__dict__)#------->{'name': 'alex', 'age': 18}
自定义元类控制类的实例化的形式

 

 因此:如果我们想控制类实例化的行为,那么需要先储备知识__call__方法的使用。

九、异常处理

 1、常见异常:

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

 

 2、异常的处理:

  • 如果异常时可以预知的,使用if来处理:
    1 AGE=10
    2 age=input('>>: ').strip()
    3 
    4 if age.isdigit():#判断是否为数字
    5     age=int(age)
    6     if age > AGE:
    7         print('太大了')
    if处理异常
  • 如果异常不可被预知,此时再采用异常处理机制,try...except。
    例子:如果setting.py中有5行文字,则不能第六次next(f),因此此时会直接跳到except 中,判断是否为该错误,如果是,则打印。

     1 try:
     2     f=open('setting.py','r',encoding='utf-8')
     3     print(next(f),end='')
     4     print(next(f),end='')
     5     print(next(f),end='')
     6     print(next(f),end='')
     7     print(next(f),end='')
     8     print(next(f),end='')
     9     print(next(f),end='')
    10     f.close()
    11 except StopIteration:
    12     print('\n出错啦')
    13 print('====>1')
    try异常处理

3、有个万能异常:Exception,他可以捕获任意异常

4、异常处理的结构

  1.   常规结构:
    1 try2     pass
    3 except KeyRrror:
    4     pass
  2.       常用结构
     1 try 2     pass#主代码
     3 except KeyError as e:
     4     pass#KeyError异常时,执行此处
     5 except IndexError as e:
     6     pass
     7 else:#主代码没有异常时,执行此处
     8     pass
     9 finally:
    10     pass#无论异常与否,最终均执行该处
  3.      主动触发异常
     1 class People:
     2     def __init__(self,name,age):
     3         if not isinstance(name,str):
     4             raise TypeError('名字必须传入str类型')
     5         if not isinstance(age,int):
     6             raise TypeError('年龄必须传入int类型')
     7 
     8         self.name=name
     9         self.age=age
    10 
    11 p=People('egon','18')
    1 Traceback (most recent call last):
    2   File "C:/Users/。。。/Desktop/python/oldboypython/day5/30try_except.py", line 111, in <module>
    3     p=People('egon','18')
    4   File "C:/Users/。。。/Desktop/python/oldboypython/day5/30try_except.py", line 106, in __init__
    5     raise TypeError('年龄必须传入int类型')
    6 TypeError: 年龄必须传入int类型
  4. 自定义异常
     1 class MyException(BaseException):
     2     def __init__(self,msq):
     3         super().__init__()
     4         self.msq=msq
     5 
     6     def __str__(self):
     7         return '%s'%self.msq
     8 try:
     9     raise MyException('wozide')
    10 except MyException as e:
    11     print(e)
    1 wozide
  5. 断言(用的较少,此处不细讲)
    格式:assert 条件

 

posted on 2018-06-03 23:02  烟易冷音未凉  阅读(319)  评论(0)    收藏  举报

导航