zoukankan      html  css  js  c++  java
  • 面向对象----类的成员 异常处理

    类的成员 异常处理

    面向对象之:类的成员

    一,细分类的成员

    class A:
        company_name = '静态变量' # 静态变量(静态字段)
        __iphone = '155xxxxxxxx'  # 私有静态变量(私有静态字段)
    
        def __init__(self, name, age): # 特殊方法
            self.name = name # 对象属性(普通字段)
            self.__age = age  # 私有对象属性(私有普通字段)
    
        def func1(self): # 普通方法
            pass
    
        def __func2(self): # 私有方法
            print(666)
    
        @classmethod # 类方法
        def class_func(cls):
            # 定义类方法,至少有一个cls参数
            print('类方法')
    
        @staticmethod # 静态方法
        def static_func():
            # 定义静态方法,无默认参数
            print('静态方法')
    
        @property # 属性
        def prop(self):
            pass
    

    二,类的私有成员

    1. 对于每一个类的成员而言都有两种形式:

      • 公有成员: 在任何地方都能访问
      • 私有成员: 只有在类的内部才能访问
    2. 私有成员和公有成员的访问限制不同:

      # 静态字段(静态属性)
      # 公有静态字段: 类可以访问(对象);类内部可以访问;派生类中可以访问(派生类和对象)
      class C:
          name = '公有静态字段'
          def func(self):
              print(C.name)
      class D(C):
          def show(self):
              print(C.name)
      print(C.name) # 类可以访问
      obj = C()
      print(obj.name) #类的对象可以访问
      obj.func() # 类的内部可以访问
      
      print(D.name) # 派生类可以访问
      obj_son = D()
      print(obj_son.name) #派生类的对象可以访问
      obj_son.show() # 派生类的内部可以访问
      
      # 私有静态字段:只能在类中访问
      class C:
          __name = '私有静态字段'
          def func(self):
              print(C.__name)
      class D(C):
          def show(self):
              print(C.__name)
      
      print(C.__name) # 类的外部不可以访问
      obj = C()
      print(obj.__name) # 类的外部不可以访问
      obj.func() # 类的内部可以访问
      
      obj_son = D()
      obj_son.show() # 不可以在派生类的内部访问
      ----------------------------------------------------
      # 普通字段(对象属性)
      # 公有普通字段: 对象可以访问;类内部可以访问;派生类中可以访问
      
      class C:
          def __init__(self):
              self.foo = '公有普通字段'
          def func(self):
              print(self.foo) # 类内部访问
      
      class D(C):
          def show(self):
              print(self.foo) # 派生类中访问
      
      obj = C()
      print(obj.foo) # 通过对象访问
      obj.func() # 类内部访问
      
      obj_son = D()
      obj_son.show() # 派生类中访问
      
      # 私有普通字段: 仅类内部可以访问
      class C:
          def __init__(self):
              self.__foo = '私有普通字段'
          def func(self):
              print(self.__foo) # 类内部访问
      
      class D(C):
          def show(self):
              print(self.__foo) # 派生类中访问
      
      obj = C()
      print(obj.__foo) # 报错,不能通过对象访问
      obj.func() # 可以在类内部访问
      
      obj_son = D()
      obj_son.show() # 报错,派生类中不能访问
      ----------------------------------------------------
      
      # 方法:
      # 公有方法: 对象可以访问;类内部可以访问;派生类中可以访问
      class C:
          def __init__(self):
              pass
          def add(self): # 公有方法
              print('in C')
      
      class D(C):
          def show(self):
              print('in D')
          def func(self):
              self.add()
          def func2(self):
              self.show()
      
      obj = C()
      obj.add() # 通过对象访问
      
      obj_son = D()
      obj_son.func2() # 类中可以访问
      obj_son.func() # 派生类中可以访问
      
      # 私有方法: 仅类内部可以访问
      class C:
          def __init__(self):
              pass
          def __add(self):
              print('in C')
      class D(C):
          def __show(self):
              print('in D')
          def func(self):
              self.__show()
          def func2(self):
              self.__add()
      
      obj = C()
      obj.__add() # 对象不可以访问
      obj_son = D()
      obj_son.func() # 类内部可以访问
      obj_son.func2() # 派生类中不能访问
      
      • 总结: 对于这些私有成员来说,他们只能在类的内部使用,不能在类的外部以及派生类中使用
      1. Ps: 非要访问私有成员的话,可以通过对象._类__属性名,但是不允许这么做.因为类在创建的时候,如果遇到了私有成员(包括私有静态字段,私有普通字段,私有方法)它会自动在前面加上_类名再保存到内存.

    三, 类的其他成员

    1. 主要就是类方法

    2. 方法包括: 普通方法,静态方法,类方法

      • 三种方法在内存中都归属于类,区别在于调用方式不同
    3. 实例方法,普通方法:

      • 定义: 第一个参数必须是实例对象,该参数名一般约定为self,通过它来传递实例的属性和方法(也可以传递类的属性和方法)
      • 调用: 只能由实例对象调用
    4. 类方法:

      • 定义: 使用装饰器@classmethod,第一个参数必须是当前类对象,该参数名一般约定为cls,通过它来传递类的属性和方法(不能传递实例的属性和方法)

      • 调用: 实例对象和类对象都可以调用

        # 使用装饰器@classmethod
        # 原则上,类方法是将类本身作为对象进行操作的方法.
        # 假设有个方法,且这个方法在逻辑上采用类本身作为对象来调用更合理,那么这个方法就可以定义为类方法.另外,如果需要继承,也可以定义为类方法.
        # 如下场景:
        # 假设我有一个学生类和一个班级类,想要实现的功能为:执行班级人数增加的操作,获得班级的总人数;学生类继承自班级类,每实例化一个学生,班级人数都能增加;最后,我想定义一些学生,获得班级中的总人数.
        # 思考:
        # 这个问题用类方法做比较合适,为什么?因为我实例化的是学生,但是如果我从学生这一个实例中获得班级总人数,在逻辑上显然是不合理的.同时,如果想要获得班级总人数,如果生成一个班级的实例也是没有必要的.
        
        class Student:
            __num = 0
            def __init__(self, name, age):
                self.name = name
                self.age = age
                Student.addNum()
        
            @classmethod # 类方法: 由类名直接调用的方法,会自动的将类名传给cls
            def addNum(cls):
                print(cls)
                cls.__num += 1
            @classmethod
            def getNum(cls):
                return cls.__num
        
        a = Student('小明', 18)
        b = Student('小红', 28)
        c = Student('小花', 38)
        print(a.getNum()) # 对象也可以调用类方法,但是会自动将其从属于的类名传给cls
        print(Student.getNum())
        
    5. 静态方法:

      • 定义: 使用装饰器@staticmethod,参数随意,没有self和cls参数,但是方法体中不能使用类或实例的任何属性和方法

      • 调用: 实例对象和类对象都可以调用

        # 静态方法: 不依赖于类,也不依赖于对象,他就是一个普通的函数,放置于类中,使结构更加清晰合理
        # 使用装饰器@staticmethod
        # 静态方法是类中的函数,不需要实例.静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作.可以理解为,静态方法是个独立的,单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护.
        import time
        class TimeTest:
            def __init__(self, hour, minute, second):
                self.hour = hour
                self.minute = minute
                self.second = second
            @staticmethod
            def showtime():
                return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
        
        print(TimeTest.showtime())
        t = TimeTest(2, 10, 10)
        nowtime = t.showtime()
        print(nowtime)
        
    6. 双下方法:

      • 定义: 双下方法是特殊方法,他是解释器提供的,由双下划线加方法名加双下划线(__方法名__)组成具有特殊意义的方法,双下方法主要是python源码程序员使用的
      • 调用: 不同的双下方法有不同的触发方式,就好比盗墓时触发的机关一样,不知不觉就触发了双下方法,例如:__init__
    7. 属性:property

      • property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

        # 例一: 求BMI指数
        # 成人的BMI数值:
        # 过轻:低于18.5
        # 正常:18.5-23.9
        # 过重:24-27
        # 肥胖:28-32
        # 非常肥胖:高于32
        # 体质指数(BMI)= 体重(kg)/ 身高**2(m)
        # EX: 70 ÷(1.75 * 1.75)= 22.86
        
        class People:
            def __init__(self, name, weight, height):
                self.name = name
                self.weight = weight
                self.height = height
            @property
            def bmi(self):
                return self.weight / self.height**2
            def bmi2(self):
                return self.weight / self.height ** 2
        
        
        p1 = People('小马', 55, 1.63)
        print(p1.bmi2()) # 虽然也可以,但是个方法,感觉不合理
        print(p1.bmi) # bmi伪装成属性来调用的,看起来更合理
        
      • 为什么使用property

        • 将一个类的函数定义成特性以后,对象再去使用的时候,根本无法察觉是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则
        • 由于新式类中具有三种访问方式,根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取,修改,删除
        class Foo:
            def __init__(self, name):
                self.name = name
            @property
            def AAA(self):
                print(self.name)
                print('get的时候运行我')
        
            @AAA.setter  # 修改,设置
            def AAA(self, value):
                self.name = value
                print(self.name)
                print('set的时候运行我')
        
            @AAA.deleter # 删除
            def AAA(self):
                del self.name
                print('delete的时候运行我')
        
        # 只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
        f1 = Foo('小马')
        f1.AAA
        f1.AAA = 'aaa'
        del f1.AAA
        -----------------------------------------------
        # 或者
        class Foo:
            def get_AAA(self):
                print('get的时候运行我')
            def set_AAA(self, value):
                print('set的时候运行我')
            def delete_AAA(self):
                print('delete的时候运行我')
            AAA = property(get_AAA, set_AAA, delete_AAA)
            # 内置property三个参数于get,set,delete一一对应
        f1 = Foo()
        f1.AAA
        f1.AAA = 'aaa'
        del f1.AAA
        
        ``````````````````````````````````````````````
        # 练习:
        class Goods:
            def __init__(self, name):
                self.name = name
                self.original_price = 100  # 原价
                self.discount = 0.8  # 折扣
            @property
            def price(self):
                # 实际价格 = 原价 * 折扣
                new_price = self.original_price * self.discount
                return new_price
            @price.setter
            def price(self, value):
                self.original_price = value
            @price.deleter
            def price(self):
                del self.original_price
        
        obj = Goods('保温杯')
        print(obj.price) # 获取商品价格
        obj.price = 200  # 修改商品的原价
        del obj.price    # 删除商品原价
        
    8. isinstance 与 issubclass

    class A:
        pass
    class B:
        pass
    obj = A()
    print(isinstance(obj, A))
    print(isinstance(obj, B))
    isinstance(a, b):判断a是否是b类(或者b类的派生类)实例化的对象
    --------------------------------------------------------
    class A:
        pass
    class B(A):
        pass
    class C(B):
        pass
    print(issubclass(B, A))
    print(issubclass(C, A))
    issubclass(a, b):判断a是否是b类(或者b类的派生类)的派生类
    -------------------------------------------------------
    # 思考:那么 list str tuple dict等这些类与Iterble类 的关系是什么?
    # 可以判断是不是可迭代对象
    from collections.abc import Iterable
    print(isinstance([1, 2, 3], list))    # True
    print(isinstance([1, 2, 3], Iterable))# True
    print(issubclass(list, Iterable))     # True
    # 由上面的例子可得.这些可迭代的数据类型.list str tuple dict等都是Iterable的子类
    

    五,type 元类

    # 按照Python的一切皆对象理论,类其实也是一个对象,
    # 那么类这个对象是从哪里实例化出来的呢?
    
    print(type('abc')) # <class 'str'>
    print(type(True))  # <class 'bool'>
    print(type(100))   # <class 'int'>
    print(type([1, 2, 3])) # <class 'list'>
    print(type({1: 'a'}))  # <class 'dict'>
    print(type((1, 2, 3))) # <class 'tuple'>
    print(type(object))    # <class 'type'>
    
    print(isinstance(object, type)) # True
    print(isinstance(list, type))   # True
    # object和list都是type类的实例对象
    
    # type元类是用于获取该对象从属于的类,而type元类比较特殊,Python原则是:一切皆对象,其实类也可以理解为'对象',而type元类又称作构建类,python中大多数内置的类(包括object)以及自己定义的类,都是由type元类实例化得来的.
    
    # type类与object类之间的关系比较独特:object是type类的实例,而type类是object类的子类.这种关系比较神奇无法使用python的代码表述,因为定义其中一个之前另一个必须存在
    

    异常处理

    一, 异常和错误

    1. 错误分两种:

      • 语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正)
      # 语法错误示范一
      if
      
      # 语法错误示范二
      def test:
          pass
      
      # 语法错误示范三
      print(haha)
      
      • 逻辑错误
      # 用户输入不完整(比如输入为空)或者输入非法(输入不是数字)
      num = input('>>:')
      int(num)
      
      # 无法完成计算
      res1 = 1 / 0
      res2 = 1 + 'str'
      
    2. 什么是异常?

      • 异常就是程序运行时发生错误的信号
    3. python中的异常种类

      # 在python中不同的异常可以用不同的类型(python中统一了类与类型,类型即类)去标识,不同的类对象标识不同的异常,一个异常标识一种错误
      
      # 触发IndexError
      l = ['egon', 'aa']
      l[3]
      
      # 触发KeyError
      dic = {'name': 'egon'}
      dic['age']
      
      # 触发ValueError
      s = 'hello'
      int(s)
      -------------------------------------------------------
      # 常见异常
      # AttributeError 试图访问一个对象没有的属性,比如foo.x,但是foo没有属性x
      # IOError 输入/输出异常:基本上是无法打开文件
      # ImportError 无法引入模块或包:基本上是路径问题或名称错误
      # IndentationError 语法错误(的子类):代码没有正确对齐
      # IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
      # KeyError 试图访问字典里不存在的键
      # KeyboardInterrupt Ctrl+C被按下
      # NameError 使用一个还未被赋予对象的变量
      # SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
      # TypeError 传入对象类型与要求的不符合
      # UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
      # 导致你以为正在访问它
      # ValueError 传入一个调用者不期望的值,即使值的类型是正确的
      ------------------------------------------------------
      # 其他异常
      # ArithmeticError
      # AssertionError
      # AttributeError
      # BaseException
      # BufferError
      # BytesWarning
      # DeprecationWarning
      # EnvironmentError
      # EOFError
      # Exception
      # FloatingPointError
      # FutureWarning
      # GeneratorExit
      # ImportError
      # ImportWarning
      # IndentationError
      # IndexError
      # IOError
      # KeyboardInterrupt
      # KeyError
      # LookupError
      # MemoryError
      # NameError
      # NotImplementedError
      # OSError
      # OverflowError
      # PendingDeprecationWarning
      # ReferenceError
      # RuntimeError
      # RuntimeWarning
      # StandardError
      # StopIteration
      # SyntaxError
      # SyntaxWarning
      # SystemError
      # SystemExit
      # TabError
      # TypeError
      # UnboundLocalError
      # UnicodeDecodeError
      # UnicodeEncodeError
      # UnicodeError
      # UnicodeTranslateError
      # UnicodeWarning
      # UserWarning
      # ValueError
      # Warning
      # ZeroDivisionError
      

    二, 异常处理

    1. 什么是异常: 异常发生之后,异常后面的代码就不会执行了

    2. 什么是异常处理:

      • python解释器检测到错误,触发异常(也允许程序员自己触发异常)程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关)如果捕捉成功则进入另外一个处理分支,执行你为其定制的逻辑,使程序不会崩溃,这就是异常处理
    3. 为什么要进行异常处理:

      • python解析器去执行程序,检测到了一个错误时,触发异常,异常触发后且没被处理的情况下,程序就在当前异常处终止,后面的代码不会运行,软件就会突然崩溃.所以必须提供一种异常处理机制来增强你程序的健壮性与容错性
    4. 如何进行异常处理:

      • 首先须知,异常是由程序的错误引起的,语法上的错误跟异常处理无关,必须在程序运行前就修正
      • 使用if判断式
      num = input('>>>:').strip()
      if num.isdecimal():
          int(num)
      elif num.isspace():
          print('输入的是空格,就执行我这里的逻辑')
      elif len(num) == 0:
          print('输入的是空,就执行我这里的逻辑')
      else:
          print('其他情情况,执行我这里的逻辑')
      # 问题一:
      # 使用if的方式只为第一段代码加上了异常处理,但这些if,跟你的代码逻辑并无关系,这样你的代码会因为可读性差而不容易被看懂
      # 问题二:
      # 这只是我们代码中的一个小逻辑,如果类似的逻辑多,那么每一次都需要判断这些内容,就会导致我们的代码特别冗长
      
      # 总结:
      # 1.if判断式的异常处理只能针对某一段代码,对于不同的代码段的相同类型的错误需要写重复的if来进行处理
      # 2.在程序中频繁的写与程序本身无关,与异常处理有关的if,会使得代码可读性极其的差
      # 3.if是可以解决异常的,只是存在1,2的问题,所以,千万不要妄下定论if不能用来异常处理
      
      • python异常处理的'私人定制'
      # python:为每一种异常定制了一个类型,然后提供了一种特定的语法结构用来进行异常处理
      # 基本语法
      try:
           被检测的代码块
      except 异常类型:
           try中一旦检测到异常,就执行这个位置的逻辑
      ---------------------------------------------------
      l1 = [1, 2, 3]
      num = input('>>>:').strip()
      try:
          num2 = int(num)
          print(l1[num2])
      except ValueError:
          print('请输入数字')
      except IndexError:
          print('超出范围')
      
      # 异常类只能用来处理指定的异常情况
      --------------------------------------------------
      # 多分支
      s1 = 'hello'
      try:
          int(s1)
      except IndexError as e:
          print(e)
      except KeyError as e:
          print(e)
      except ValueError as e:
          print(e)
      
      --------------------------------------------------
      # 万能异常: 可以捕获任意异常
      s1 = 'hello'
      try:
          int(s1)
      except Exception as e:
          print(e)
      
      # 如果我们需要的效果是,无论出现什么异常,统一丢弃,或者使用同一段代码逻辑去处理,那么只需要一个Exception就够了
      # 如果你想要的效果是,对于不同的异常我们需要定制不同的处理逻辑,那就需要用到多分支了
      
      • 异常处理的其他代码
      s1 = 'hello'
      try:
          int(s1)
      except IndexError as e:
          print(e)
      except KeyError as e:
          print(e)
      except ValueError as e:
          print(e)
      except Exception as e:
          print(e)
      else:
          print('try内代码块没有异常则执行我')
      finally: # 如果不处理异常,在终止程序之前之前会执行finally
          print('无论异常与否,都会执行该模块,通常是进行清理工作')
      
      # finally的应用场景: 文件读写,数据库连接
      
      # 函数中的finally: 在return先执行finally
      def func():
          try:
              a = 1
              b = 2
              return a + b
          finally: # 在return先执行finally
              print(666)
      print(func())
      -------------------------------------------------
      # 主动触发异常
      try:
          raise TypeError('类型错误')
      except Exception as e:
          print(e)
      -------------------------------------------------
      # 自定义异常
      class EvaException(BaseException):
          def __init__(self, msg):
              self.msg = msg
          def __str__(self):
              return self.msg
      try:
          raise EvaException('类型错误')
      except EvaException as e:
          print(e)
      
      -------------------------------------------------
      # 断言
      # assert 条件
      assert 1 == 1 # 条件成立继续执行下面的代码
      assert 1 == 2 # 条件不成立会抛出AssertionError异常
      
      • try...except的方式比较if方式的好处
        1. 把错误处理和真正的工作分开来
        2. 代码更易组织,更清晰,复杂的工作任务更容易实现
        3. 毫无疑问,更安全了,不至于由于一些小的疏忽而使程序意外崩溃了
      • 什么时候用异常处理?
        • 异常处理不能经常使用: 异常处理耗费性能,有些错误是需要进行分流使用,代码的可读性变差.关键的节点去使用异常处理
  • 相关阅读:
    神经网络与数字货币量化交易系列(1)——LSTM预测比特币价格
    FMZ发明者量化平台回测机制说明
    使用JavaScript实现量化策略并发执行
    数字货币期货与现货JavaScript量化策略代码详解汇总
    极简比特币高频策略机器人
    爬虫爬取币安公告自动出售将要下架币策略
    Deribit交易所 websocket API 连接范例
    极简版OKEX比特币跨期对冲策略
    OKEX websocket API 连接Python范例
    Vmare安装Linux 虚拟机流程
  • 原文地址:https://www.cnblogs.com/maqian/p/11949652.html
Copyright © 2011-2022 走看看