python09-面向对象(二) & 异常

面向对象

  • 回顾:

    • 反射:以字符串的形式去某个对象(模块,类,对象)操作它的成员(python中,一切皆对象)
    # 从模块中获取属性
    module = __import__('commons') # 引入commons模块
    if __name__ == '__main__':
        if hasattr(module, 'f1'):
            # print('ok')
            f1 = getattr(module, 'f1')
            ret = f1()
            print('ret =', ret)
    
    # 从类中获取属性
    class Cat:
        desc = 'YHH'
        def __init__(self, name):
            self.name = name
    
        def show(self):
            print(self.name)
    
    show = getattr(Cat, 'show')
    show(Cat('yhh'))
    
    # 从对象中获取属性
    cat = Cat('yhh')
    show = getattr(cat, 'show')
    show()
    
    • 多继承面试题:
    # 继承关系:
    # A(ooo) --> D
    # B(ooo) --> C(xxx,ooo) --> D
    class D(A,C):
        pass
    dog = D() # 创建D实例
    dog.xxx() # 调用xxx方法,只有C有,调用C的
    # 在xxx方法内部调用ooo方法,虽然C也有ooo方法
    # 但是函数内部调用方式为:self.ooo()
    # 根据继承的调用顺序,虽有调用的是A的ooo方法
    # 看别人的代码时,惊颤遇到这个问题--方法由谁发起的就由谁开始找
    
    • 继承中调用构造方法
      • 创建对象时会调用对象的__init__方法
      • 如果对象没有__init__方法,回去调用父类的构造方法
    class Animal:
        def __init__(self):
            print('Animal')
    class Cat(Animal):
        def __init__(self):
            print('Cat')
    cat = Cat() # Cat
    # =====================
    class Animal:
        def __init__(self):
            print('Animal')
    
    class Cat(Animal):
        # def __init__(self):
        #     print('Cat')
        pass
    
    cat = Cat() # Animal
    
    • 调用父类的构造方法
      • 调用父类的构造方法有两种方式:
    # 一:第一个参数为当前类,第二个参数为self
    # 表示找到Cat的父类并执行构造方法
    class Animal:
        def __init__(self):
            print('Animal')
    
    class Cat(Animal):
        def __init__(self):
            print('Cat')
            super(Cat, self).__init__()
    
    cat = Cat() # Cat Animal
    # 二:主动去调用父类的构造方法
    class Animal:
        def __init__(self):
            print('Animal')
    
    class Cat(Animal):
        def __init__(self):
            print('Cat')
            Animal.__init__(self)
    cat = Cat() # Cat Animal
    
  • 成员:

    • 反射:
      • 通过类-对象指针也能找到类中的方法
    class Cat():
        def __init__(self, name):
            self.name = name
        def show(self):
            print(self.name)
    
    cat = Cat('yhh')
    ret = hasattr(Cat, 'show') # 类中的方法
    print(ret) # True
    ret = hasattr(cat, 'name') # 对象的属性
    print(ret) # True
    ret = hasattr(cat, 'show') # 对象的方法
    print(ret) # True
    
    • 手动实现从导入模块到创建对象再获取对象属性的反射
    module = __import__('commons', fromlist=True)
    class_name = getattr(module, 'Cat')
    cat = class_name('yhh')
    name = getattr(cat, 'name')
    print(name) # yhh
    method = getattr(cat, 'show')
    method()
    
    • 静态字段:静态字段存在类中

      • 如果一个类中所有的对象都用共同的字段且想通过,可将此字段设置为静态字段
      • 在类中存在的字段为静态字段,在对象中存在的字段为普通字段
      class Province:
          country = 'China' # 静态字段
      
    • 类的成员:普通字段,普通方法,静态字段,静态方法,类方法,特性

      • 约定俗成:普通字段,普通方法由对象访问,静态字段,静态方法,类方法由类访问
      • 通过类访问普通方法需要参数需要传入对象
    • 静态方法

    class Cat:
        @staticmethod
        def show():
            pass
    
    • 类方法
      • 类方法其实相当于静态方法的另一种形式,只是调用时python自动将类名传给方法
    class Cat:
        @classmethod
        def show(cls):
            print(cls)
    
    Cat.show()
    
    • 特性(属性)

      • 执行方法一般为对象名.方法名()来调用,如果在定义方法的时候加上@property,那么调用该方法是不需要加上括号(前提是该方法不需要参数)
      • 当方法名和字段名相同,写在后面的会覆盖前面的,一般不会这么写
      • 作用:把方法伪造成字段来操作(比较鸡肋)
      class Cat:
          def __init__(self, name):
              self.name = name
          @property
          def show(self):
              print(self.name)
      
      cat = Cat('yhh')
      cat.show
      
      cat.name # 获取字段
      cat.name = 'newName' # 修改字段
      cat.show    # 通过特性,以字段的形式调用函数
      cat.show = 'haha'   # 报错
      # 如果想要不报错,则修改代码
      class Cat:
      def __init__(self, name):
          self.name = name
      @property
      def show(self):
          print(self.name)
      @show.setter
      def show(self,arg):
          self.name = arg
      
      cat = Cat('yhh')
      cat.show
      cat.show = 'catName'
      cat.show
      # 定义一个和@property方法名一样的方法,方法加上@方法名.setter就可以使得方法可以像修改属性一样传递参数
      
  • 修饰符:

    • 在方法或者字段前加上__表示私有
    • 私有的方法和属性不能被继承,只有自己能够访问
    • 私有也可以获取:
      • python中有个特殊的方法,私有的实行和方法也可以获取,一般不会这么用
    class Cat:
        __xo = 'xo'
        def __show(self):
            print('show')
        def pub(self):
            self.__show()
    cat = Cat()
    print(cat._Cat__xo)
    # 对象._类名__属性名或方法
    
  • 特殊方法:

    • __init__:构造方法,创建对象的时候调用
    • __del__:解析器销毁对象的时候调用
    • __call__:当调用对象名()的时候调用
      • Django,web框架的源码用到
    class Cat:
        def __init__(self):
            print('创建对象的时候调用')
        def __call__(self, *args, **kwargs):
            print('对象名()调用')
    
    cat = Cat() # 调用构造方法
    cat() # 调用call方法
    
    • __setitem__,__getitem__,__delitem__
      • 自定义section会用到
    • __str__
    li = list([11, 22, 33, 44]) # ls是一个对象
    print(li[1]) # 对象名[index]
    li[1] = 'index' # 对象名[index] = value
    del li[1] # del 对象名[index]
    print(li) # 打印对象
    print(str(li)) # str(对象名)
    
    # li是list类的一个对象,通过类似的,我们自己创建的一个对象
    
    class Cat:
        def __getitem__(self, item):
            print('getitem', item)
        def __setitem__(self, key, value):
            print('setitem', key, value)
        def __delitem__(self, key):
            print('delitem', key)
    
    cat = Cat()
    cat[1] # getitem 1
    cat['k1'] # getitem k1
    cat['key'] = 'value' # setitem key value
    del cat['key'] # delitem key
    
    # 通过切片时:
    cat = Cat()
    cat[1:2:3] # getitem slice(1, 2, 3)
    cat[1:2:3] = 123 # setitem slice(1, 2, 3) 123
    del cat[1:2:3] # delitem slice(1, 2, 3)
    
    # python2.7中操作切片时会调用:
    # __getslice__
    # __setslice__
    # __delslice__
    # 在python3.x中会调用:
    # __getitem__
    # __setitem__
    # __delitem__
    
    #==========================
    # 直接打印对象会调用对象的__str__()
    # 将对象转字符串也会调用__str__()
    class Cat:
        def __str__(self):
            return '调用str方法'
    
    cat = Cat()
    print(cat)
    print(str(cat))
    
    • dict:查看成员(比较重要)
      • 应用:自定义form框架的时候用
      • 获取对象里面所有的字段
    class Cat:
        def __init__(self, name):
            self.name = name
        def show(self):
            pass
        def fun(self):
            pass
    
    ret = Cat.__dict__
    print(ret)# {'__module__': '__main__', 'fun': , 'show': , '__weakref__': , '__dict__': , '__init__': , '__doc__': None}
    obj = Cat('yhh')
    ret = obj.__dict__
    print(ret) # {'name': 'yhh'}
    
    • iter:
      • for循环对象时会调用__iter__方法
    li = list([11, 22, 33, 44, 55])
    for item in li:
        print(item)
    # li是list类的对象,for循环li对象时会遍历得到结果
    # 自定义对象遍历:
    class Cat:
        def __iter__(self):
            yield 11
            yield 22
            yield 33
            yield 44
    
    cat = Cat()
    for item in cat:
        print(item)
    
    • __new__ & __metaclass__

      • python中一切皆对象,类是对象,模块是对象,类创建的也是对象
      • 解析器解析到class关键字就会创建类对象(默认由type创建)
      class Cat:
          __metaclass__ = xxx # 表示由xxx来创建这个类
      # 创建类:
      Cat = type(Cat, (object,),{"fun1":func}
      # type(类名,(基类,..),{成员})
      

异常

  • 编程难免遇到报错,如web网页尽量避免大黄页,应该让用户看到有好的错误页面.
try:
    # 需要保护的代码
    li = [11, 2, 3]
    ret = li[5]
except IndexError as IE:
    # 遇到异常时执行的代码块
    print(IE)
except Exception as e:
    # 遇到异常时执行的代码块
    print(type(e))
else:
    # 没有异常时执行的代码块
    print('no exception')
finally:
    # 不管有没有异常都会执行的代码块
    print('finally')
  • 异常分类:
    • 所有异常都是Exception的派生类
  • 主动触发异常
raise Exception('异常')

try:
    raise Exception('发生异常')
except Exception as e:
    pass
  • 断(意义不大)
assert 1 == 1
assert 2 == 1
# 如果为真,则真
# 如果为假,则抛异常
# 做测试用,限制软件的运行环境等

你可能感兴趣的:(python09-面向对象(二) & 异常)