python面向对象之类的成员及异常处理

1.面向对象之:类的成员

  1. 类的结构细分

    # 类的结构分为属性和方法两大类,其中又可以细分为下面这几种
    class A:
        company_name = '老男孩教育'  # 静态变量(静态字段)
        __iphone = '1353333xxxx'  # 私有静态变量(私有静态字段)
        def __init__(self,name,age): # 特殊方法
            self.name = name  # 对象属性(普通字段)
            self.__age = age  # 私有对象属性(私有普通字段)
        def func1(self):  # 普通方法
            pass
        def __func(self): # 私有方法
            print(666)
        @classmethod  # 类方法
        def class_func(cls):
            """ 定义类方法,至少有一个cls参数 """
            print('类方法')
        @staticmethod  # 静态方法
        def static_func():
            """ 定义静态方法 ,无默认参数"""
            print('静态方法')
        @property  # 属性
        def prop(self):
            pass
  2. 类的私有成员 *

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

    • 公有成员,在任何地方都能访问
    • 私有成员,只有在类内部才能访问,不能在类外部以及派生类中使用.

    私有成员和公有成员的访问限制不同

    静态字段(静态属性)

    • 公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
    • 私有静态字段:仅类内部可以访问;
    #### 公有静态字段
    class C:
        name = "公有静态字段"
        def func(self):
            print(C.name)
    class D(C):
        def show(self):
            print(C.name)
    
    print(C.name)         # 类名访问
    
    obj = C()
    obj.func()     # 类内部可以访问
    
    obj_son = D()
    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()
    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()
    
    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()
    
    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.show()
    obj = D()
    obj.show()  # 通过对象访问   
    obj.func()  # 类内部访问    
    obj.add()  # 派生类中访问  
    
    #### 私有方法
    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()
    obj = D()
    obj.__show()  # 不能通过对象访问
    obj.func()  # 类内部可以访问
    obj.__add()  # 派生类中不能访问

    *ps:非要访问私有成员的话,可以通过 对象._类__属性名,但是绝对不允许!!!*

    *为什么可以通过._类__私有成员名访问呢?因为类在创建时,如果遇到了私有成员(包括私有静态字段,私有普通字段,私有方法)它会将其保存在内存时自动在前面加上_类名.*

  3. 类的其他成员

    这里的其他成员主要就是类方法:

    方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。

    实例方法

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

    类方法

    定义:使用装饰器`@classmethod`。第一个参数必须是当前类对象,该参数名一般约定为“`cls`”,通过它来传递类的属性和方法(不能传实例的属性和方法)
    
    调用:实例对象和类对象都可以调用。
    '''
    原则上,类方法是将类本身作为对象进行操作的方法。假设有个方法,且这个方法在逻辑上采用类本身作为对象来调用更合理,那么这个方法就可以定义为类方法。另外,如果需要继承,也可以定义为类方法。
    如下场景:
    假设我有一个学生类和一个班级类,想要实现的功能为:
        执行班级人数增加的操作、获得班级的总人数;
        学生类继承自班级类,每实例化一个学生,班级人数都能增加;
        最后,我想定义一些学生,获得班级中的总人数。
    思考:这个问题用类方法做比较合适,为什么?因为我实例化的是学生,但是如果我从学生这一个实例中获得班级总人数,在逻辑上显然是不合理的。同时,如果想要获得班级总人数,如果生成一个班级的实例也是没有必要的。
    '''
    class Student:   
        __num = 0
        def __init__(self,name,age):
            self.name = name
            self.age= age
            Student.addNum()        
        @classmethod
        def addNum(cls):
            cls.__num += 1
        @classmethod
        def getNum(cls):
            return cls.__num
    
    a = Student('太白金星', 18)
    b = Student('武sir', 36)
    c = Student('alex', 73)
    print(Student.getNum())

    静态方法

    定义:使用装饰器`@staticmethod`。参数随意,没有“self”和“`cls`”参数,但是方法体中不能使用类或实例的任何属性和方法;
    
    调用:实例对象和类对象都可以调用。
    '''
    静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护。
    '''
    # 譬如,我想定义一个关于时间操作的类,其中有一个获取当前时间的函数。
    
    import time
    class TimeTest(object):
        def __init__(self, hour, minute, second):
            self.hour = hour
            self.minute = minute
            self.second = second
        @staticmethod
        def showTime():
            return time.strftime("%H:%M:%S", time.localtime())
    print(TimeTest.showTime())
    t = TimeTest(2, 10, 10)
    nowTime = t.showTime()
    print(nowTime)
    '''
    如上,使用了静态方法(函数),然而方法体中并没使用(也不能使用)类或实例的属性(或方法)。若要获得当前时间的字符串时,并不一定需要实例化对象,此时对于静态方法而言,所在类更像是一种名称空间。
    其实,我们也可以在类外面写一个同样的函数来做这些事,但是这样做就打乱了逻辑关系,也会导致以后代码维护困难。
    '''

    双下方法

     定义:双下方法是特殊方法,他是解释器提供的 由双下划线加方法名加双下划线 __方法名__的具有特殊意义的方法,双下方法主要是python源码程序员使用的,

     我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码。

     调用:不同的双下方法有不同的触发方式,就好比盗墓时触发的机关一样,不知不觉就触发了双下方法,例如:__init__

  4. 属性(特殊) **

    # 什么是特性property?
     property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
    
    例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
    
    成人的BMI数值:
    过轻:低于18.5
    正常:18.5-23.9
    过重:24-27
    肥胖:28-32
    非常肥胖, 高于32
      体质指数(BMI)=体重(kg)÷身高^2(m)
      EX:70kg÷(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)
    
    p1=People('egon',75,1.85)
    print(p1.bmi)
    '''
    为什么要用property
    将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则
    '''
    # 由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
    class Foo:
        @property    # 模仿属性调用
        def AAA(self): 
            print('get的时候运行我啊')
        @AAA.setter   # 模仿属性修改
        def AAA(self,value):  
            print('set的时候运行我啊')
        @AAA.deleter   # 模仿属性删除
        def AAA(self):
            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(object):
        def __init__(self):
            # 原价
            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.deltter
        def price(self, value):
            del self.original_price
    obj = Goods()
    obj.price         # 获取商品价格
    obj.price = 200   # 修改商品原价
    del obj.price     # 删除商品原价
  5. isinstance issubclass

    # isinstance(a,b):判断a是否是b类(或者b类的派生类)实例化的对象
    class A:
        pass
    class B(A):
        pass
    obj = B()
    print(isinstance(obj,B))  # True  obj是B类的实例化对象
    print(isinstance(obj,A))  # True  obj是A的子类B的实例化对象
    
    # issubclass(a,b): 判断a类是否是b类(或者b的派生类)的派生类
    class A:
        pass
    class B(A):
        pass
    class C(B):
        pass
    print(issubclass(B,A)) # True  B是A的子类
    print(issubclass(C,A)) # True  C是A的子类B的子类
    
    思考:那么 list str tuple dict等这些类与 Iterble类 的关系是什么?
    from collections 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的子类。
  6. 元类(type)(type与object的区别)

    一个需要了解又难以理解的类:元类type。
    # 按照Python的一切皆对象理论,类其实也是一个对象,那么类这个对象是从哪里实例化出来的呢?
    
    print(type('abc'))
    print(type(True))
    print(type(100))
    print(type([1, 2, 3]))
    print(type({'name': '太白金星'}))
    print(type((1,2,3)))
    print(type(object))
    
    class A:
        pass
    
    print(isinstance(object,type))
    print(isinstance(A, type))
    '''
    type元类是获取该对象从属于的类,而type类比较特殊,Python原则是:一切皆对象,其实类也可以理解为'对象',而type元类又称作构建类,python中大多数内置的类(包括object)以及自己定义的类,都是由type元类创造的。
    * 而type类与object类之间的关系比较独特:object是type类的实例,而type类是object类的子类,这种关系比较神奇无法使用python的代码表述,因为定义其中一个之前另一个必须存在。所以这个只作为了解。
    '''

2.异常处理 ***

  1. 程序中的错误分为:语法错误和逻辑错误

    写程序时,语法错误是要自己避免的,逻辑错误可能是写代码时没考虑到的情况

  2. 什么是异常

    异常就是程序运行时发生错误的信号,在python中,错误触发的异常如下

    Traceback (most recent call last):
      File "E:/pycharm projects/一脸懵逼/练习.py", line 101, in <module>
        print(num)
    NameError: name 'num' is not defined
    '''
    Traceback (most recent call last):
      File "E:/pycharm projects/一脸懵逼/练习.py", line 101, in <module>
        print(num)
    '''
    # 这是错误信息的追踪
    # NameError 这是错误类型
    # name 'num' is not defined  这是错误的原因
  3. python中的异常种类

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

    1.什么是异常?

    代码发生异常, 异常之后的代码就不执行了

    2.什么是异常处理

    python解释器检测到错误,触发异常(也允许程序员自己触发异常)

    程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关)

    如果捕捉成功则进入另外一个处理分支,执行你为其定制的逻辑,使程序不会崩溃,这就是异常处理

    3.为什么要进行异常处理?

    python解析器去执行程序,检测到了一个错误时,触发异常,异常触发后且没被处理的情况下,程序就在当前异常处终止,后面的代码不会运行,谁会去用一个运行着突然就崩溃的软件。

    所以你必须提供一种异常处理机制来增强你程序的健壮性与容错性

    4.如何进行异常处理?

    首先须知,异常是由程序的错误引起的,语法上的错误跟异常处理无关,必须在程序运行前就修正

    ### 第一种:使用if语句
    num1=input('>>: ') #输入一个字符串试试
    if num1.isdigit():
        int(num1) # 我们的正统程序放到了这里,其余的都属于异常处理范畴
    elif num1.isspace():
        print('输入的是空格,就执行我这里的逻辑')
    elif len(num1) == 0:
        print('输入的是空,就执行我这里的逻辑')
    else:
        print('其他情情况,执行我这里的逻辑')
    
    '''
    使用if语句处理异常有两个问题
    问题一:使用if的方式我们只为第一段代码加上了异常处理,但这些if,跟你的代码逻辑并无关系,这样你的代码会因为可读性差而不容易被看懂
    问题二:这只是我们代码中的一个小逻辑,如果类似的逻辑多,那么每一次都需要判断这些内容,就会倒置我们的代码特别冗长。
    '''
    '''
    总结:
    1.if判断式的异常处理只能针对某一段代码,对于不同的代码段的相同类型的错误你需要写重复的if来进行处理。
    2.在你的程序中频繁的写与程序本身无关,与异常处理有关的if,会使得你的代码可读性极其的差
    3.if是可以解决异常的,只是存在1,2的问题,所以,千万不要妄下定论if不能用来异常处理。
    '''
    ### 第二种:使用异常处理语法
    基本语法
    try:
         被检测的代码块
    except 异常类型:
         try中一旦检测到异常,就执行这个位置的逻辑
    # 应用举例:
    # 文件读取时
    try:
        f = open('a.txt')
        g = (line.strip() for line in f)
        print(next(g))
        print(next(g))
        print(next(g))
        print(next(g))
        print(next(g))
    except StopIteration:
        f.close()
    '''
    next(g)会触发迭代f,依次next(g)就可以读取文件的一行行内容,无论文件a.txt有多大,同一时刻内存中只有一行内容。
    提示:g是基于文件句柄f而存在的,因而只能在next(g)抛出异常StopIteration后才可以执行f.close()
    '''
    # 异常类只能用来处理指定的异常情况.
    # 未捕获到异常,程序直接报错
    # 单分支异常处理
    s1 = 'hello'
    try:
        int(s1)
    except IndexError as e:
        print e
    # 多分支异常处理
    s1 = 'hello'
    try:
        int(s1)
    except IndexError as e:
        print(e)
    except KeyError as e:
        print(e)
    except ValueError as e:
        print(e)
    
    ### 第三种: 万能异常:Exception.
    他可以捕获任意异常,即:
    s1 = 'hello'
    try:
        int(s1)
    except Exception as e:
        print(e)
    你可能会说既然有万能异常,那么我直接用上面的这种形式就好了,其他异常可以忽略
    你说的没错,但是应该分两种情况去看
    1.如果你想要的效果是,无论出现什么异常,我们统一丢弃,或者使用同一段代码逻辑去处理他们,那么确实是只用一个Exception就足够了。
    s1 = 'hello'
    try:
        int(s1)
    except Exception,e:
        '丢弃或者执行其他逻辑'
        print(e)
    # 如果你统一用Exception,没错,是可以捕捉所有异常,但意味着你在处理所有异常时都使用同一个逻辑去处理(这里说的逻辑即当前expect下面跟的代码块)
    
    2.如果你想要的效果是,对于一些异常我们需要定制不同的处理逻辑,其他的异常统一处理, 那就需要用到多分支了。
    s1 = 'hello'
    try:
        int(s1)
    except IndexError as e: 
        print(e) # 遇到IndexError异常执行这里的代码
    except KeyError as e:
        print(e) # 遇到KeyError异常执行这里的代码
    except ValueError as e:
        print(e) # 遇到ValueError异常执行这里的代码
    except Exception as e:
        print(e) # 其他异常执行这里的代码
    
    ##### 异常的其他机构
    try:
        f = open('a.txt')
        g = (line.strip() for line in f)
        print(next(g))
        print(next(g))
        print(next(g))
        print(next(g))
        print(next(g))
    except StopIteration as e:
        print(e)
    else:
        print('try内代码块没有异常则执行我')
    finally:
        f.close()
        print('无论异常与否,都会执行该模块,通常是进行清理工作')
    # 当程序遇到异常时,在整个程序终止之前,执行finally里的代码
  5. 主动抛出异常

    # 主动抛出异常: raise
    raise Exception('fdkslafjdslkf')
    
    # 断言: assert 条件  # 源码上经常见到assert.
    assert 1 == 2  # 条件成立执行下面的代码,不成立抛出异常
    print(11)
    print(22)
    print(33)
  6. 自定义异常

    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)
  7. 异常处理怎么用?

    异常处理总结:
    # 异常处理不能经常使用:异常处理耗费性能.有些错误是需要进行分流使用.代码的可读性变差.
    # 关键节点使用.

转载于:https://www.cnblogs.com/changyifei-8/p/11178347.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值