• day08面向对象(二)


    Python 面向对象

     本章内容简介:

    1. 类的成员:
        1) 字段 : 普通字段、静态字段;

        2) 方法 : 普通方法、静态方法、类方法;

        3) 属性 : 普通属性(获取、设置、删除);

    2. 成员修饰符:

        1)公有的       任何 都可以调用;

        2)私有的       仅类自己内部可以调用;可以用一个另类的方法调用,就是 obj._类名__私有(字段等),好吧,知道能这么用就行了,最好忘了它。

    3. 类的特殊成员:

        __init__      构造方法;  

        __dic__      注释文档查看,函数下加引号写的第一位置,会被此成员读取;

        __call__      变量加括号执行call方法;

        __str__      将内存地址的内容,读取成str内容;     

        __setitem__    

        ......

    4. 面向对象的其它内容:

        -- isinstance    判断一个对象是否属于某个类;

        -- issubclass    判断一个类是否属于某个类的子类;

        -- 执行父类构造方法

        -- 应用:

            自定义类型,对字典进行补充,有序字典,源码的扩展;

    5. 设计模式之单例模式;

    6. 异常处理:

        try  ===  except === = finally

    一. 类的成员

    • 字段

    1. 普通字段,实例:

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

    代码解析:

      name就是普通字段,当Foo函数,被实例化时,如:obj = Foo('hailong') ,对象obj 就使用了name普通字段,普通字典默认被对象使用,所以普通字段是保存在对象里的;

    2. 静态字段,实例:

    class Province:
        country = "中国" # 静态字段,保存在类里,节省内存空间;
    
        def __init__(self,name):
            self.name = name
    
    country = Province.country
    tj = Province("天津")
    
    print(tj.country ,'	',country)

    代码解析:

      country是静态字段,如上实例所示,静态字段,类可以调用,对象也可以调用,其它语言里是不允许的,之所以对象可以调用静态字段,是因为对象里的类对象指针(对象去数据时,是先从自己本身找,找不到,通过类对象指针到类里找)通过这种方式来访问的;通常情况下,我们要使用类来调用静态字段;

    总结:

      普通字段,用对象来访问; 静态字段,使用类来访问,实在没办法时才用对象访问;

      当执行程序时,如果没创建对象时,普通字段不会加载到内存,但是静态字段默认会加载到内存;

    •  方法

    1. 普通方法,实例:

    class Province:
        country = "中国" 
    
        def __init__(self,name):
            self.name = name
    
        def show(self):  # 方法属于类,是由对象调用的
            print(self.name)
    
    tj = Province("天津")
    tj.show()

    代码解析:

      方法属于类,普通方法存在类里,是由对象调用的;

    2. 静态方法,实例:

    class Province:
        country = "中国" # 静态字段,保存在类里,节省内存空间;
    
        def __init__(self,name):
            self.name = name
    
        @staticmethod    # 静态方法,是由类调用的
        def func(arg1,arg2):
            print(arg1,arg2)
    
    Province.func(123,'qcc'

    代码解析:

      静态方法是由类调用的,就是方法去掉self参数后,是用装饰器staticmethod,传参自定义,不需要创建对象,就可以执行的方法。用于一些不通用的方法,这样节省内存空间;

      相当于Python的函数;

    3. 类方法,实例:

    class Province:
        country = "中国" # 静态字段,保存在类里,节省内存空间;
    
        def __init__(self,name):
            self.name = name
    
        @classmethod
        def f1(cls):
            print(cls)
    
    Province.f1()

    代码解析:

      类方法是由类调用的,它有一个默认的形式参数cls,cls相当于类名;

    • 属性

    1. 普通属性,实例:

    class Pager:
        def __init__(self,count_pager):
            self.count_pager = count_pager
    
        @property  # 普通属性
        def all_pager(self):
            a1,a2=divmod(self.count_pager,10)
            if a2 == 0:
                return a1
            return a1+1
    
    p = Pager(101)
    print(p.all_pager)  # 执行普通属性,不用加括号了

    代码解析:

      普通属性,具有方法的访问写形式,具有字段的访问形式。 相当于方法去掉括号,由对象调用;

    2. 属性操作(设置)实例:

    class Pager:
        def __init__(self,count_pager):
            self.count_pager = count_pager
    
        @property
        def all_pager(self):
            a1,a2=divmod(self.count_pager,10)
            if a2 == 0:
                return a1
            return a1+1
    
        @all_pager.setter
        def all_pager(self,value):
            print(value)
    
    p = Pager(101)
    p.count_pager = 211  # 设置属性,对属性的方法进行setter;
    print(p.count_pager)

    代码解析:

      对象生成后,count_pager 根据类参数定义一个值,当想要使用一个新值时,需要使用到设置属性,给字段count_pager重新赋值,使用普通属性方法setter装饰器,重新给字段赋值;

    3. 属性操作(删除)实例:

    class Pager:
        def __init__(self,count_pager):
            self.count_pager = count_pager
    
        @property
        def all_pager(self):
            a1,a2=divmod(self.count_pager,10)
            if a2 == 0:
                return a1
            return a1+1
    
        @all_pager.setter
        def all_pager(self,value):
            print(value)
    
        @all_pager.deleter
        def all_pager(self):
            print("del all_pager")
    
    p = Pager(101)
    p.count_pager = 211 #设置方法,会调用all_pager.setter下的方法;
    print(p.count_pager)  
    del p.all_pager # del 是个语法,会调用all_pager.deleter下的方法;
    

    property的构造方法中有个四个参数

    • 第一个参数是方法名,调用 对象.属性 时自动触发执行方法
    • 第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
    • 第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
    • 第四个参数是字符串,调用 对象.属性.__doc__ ,此参数是该属性的描述信息

    属性的另一种写法

    class Pager:
        def __init__(self,name):
            self.name = name
    
        def f1(self):
            return 123
    
        def f2(self,value):
            print(value)
    
        def f3(self):
            print('del f1') # 还没弄明白,具体怎么用
    
        foo = property(fget=f1,fset=f2,fdel=f3)
    
    obj = Pager('hailong')
    res = obj.foo
    print(res)
    obj.foo = 456
    del obj.foo
    

    代码解析:

      不用加装饰器了,直接给静态字段赋值,使用property,来完成属性的功能; 

    由属性的定义和调用要注意一下几点:

    • 定义时,在普通方法的基础上添加 @property 装饰器;
    • 定义时,属性仅有一个self参数
    • 调用时,无需括号
                 方法:foo_obj.func()
                 属性:foo_obj.prop

    注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象

             属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。

    二.  成员修饰符

     1. 公有的,实例:

    class Province(object):
    
        def __init__(self,name):
            self.name = name
    
    
    hb = Province("河北")
    print(hb.name)  #name是公有的,任何对象都可以调用;
    

    代码解析:

      这个例子里,name就是公共的,任何基于Province创建的对象都能使用;

    2. 私有修饰符,实例(一):

    class Province(object):
    
        def __init__(self,name):
            self.__name = name
    
        def f1(self):
            print(self.__name)
    
    hb = Province("河北")
    hb.f1()
    
    # print(hb.__name) # 报错 AttributeError: 'Province' object has no attribute '__name'
    

    代码解析:

      当把公有的,加上双下划线后,就变成私有的了,这时外部不能调用,只能是类里的方法可以调用;只有自己访问可以,不能被继承;

    实例(二):

    class Province(object):
        __paw = 123
        def __init__(self,name):
            self.__name = name
    
        def f1(self):
            print(Province.__paw)
    
        @staticmethod
        def f2():
            print(Province.__paw)
    
    hb = Province("河北")
    hb.f1()       # 通过变量调用使用了私有字段的方法;
    Province.f2() #直接用类调用,静态方法里的私有字段;
    hb.f2()  # 也可以成功,但是不建议这样使用;
    Province.f1() # 不可以在外部直接使用类里的私有字段,报错 TypeError: f1() missing 1 required positional argument: 'self'
    

    三. 特殊成员

    上文介绍了Python的类成员以及成员修饰符,从而了解到类中有字段、方法和属性三大类成员,并且成员名前如果有两个下划线,则表示该成员是私有成员,私有成员只能由类内部调用。无论人或事物往往都有不按套路出牌的情况,Python的类成员也是如此,存在着一些具有特殊含义的成员,详情如下:

    1. del、call 和  str方法:

    class Foo(object):
    
        instance = None
        def __init__(self,name,age):
            self.name=name
            self.age = age
    
        # 析构方法,系统垃圾回收之前执行这个方法;
        def __del__(self):
            pass
    
        #
        def __call__(self, *args, **kwargs):
            print("call")
    
        #
        def __str__(self):
            return "%s - %s" % (self.name,self.age)
    
    obj = Foo("hailong",23)
    obj1 = Foo("eric",23)
    print(obj)       # 执行时,调用了str方法
    res = str(obj1)  # 执行时,调用了str方法
    obj()  # 变量加括号,执行call方法;
    Foo("hailong",23)() # 类执行,加括号执行call方法;
    print(obj1)
    

    2. add 、 dict 方法:

    class Foo:
        def __init__(self,name,age):
            self.name = name
            self.age  = age
    
        def __add__(self, other):
            temp = "%s - %d" % (self.name,other.age)
            return temp
    
    obj1= Foo("hailong",23)
    obj2= Foo('eric',19)
    res = obj1 + obj2     # 执行add方法;
    print(res)
    print(obj1.__dict__)  # 返回obj1封装的内容,字典格式输出;
    

    如果执行  类.__dict__ 会打印出类里封装的所有的成员,一般用于对象的封装查看;

    3. getitem、setitem和delitem方法:

    class Foo:
        def __init__(self,name,age):
            self.name = name
            self.age  = age
    
        def __getitem__(self, item):
            return 123
    
        def __setitem__(self, key, value):
            print(key,value)
    
        def __delitem__(self, key):
            print("del %s" % key)
    
    obj1= Foo("hailong",23)
    res = obj1['abc']  # 执行getitem方法
    print(res,"----")
    obj1['k1'] = 122   # 执行了setitem方法 ,执行结果是k1 122
    print(obj1.__dict__) # obj1没有任何改变;
    del obj1['k1']      # 执行delitem方法,

    对象后加括号执行call方法,加上中括号执行 getitem方法。。。

    4. getitem 切片方法:

    class Foo:
        def __init__(self,name,age):
            self.name = name
            self.age  = age
    
        def __getitem__(self, item):
            print(item.start)
            print(item.stop)
            print(item.step)
            return 123
    
        def __setitem__(self, key, value):
            print(key,value)
    
    obj1= Foo("hailong",23)
    # res = obj1['abc']  # 字符串方法没有切片start等位置属性;
    res1 = obj1[0:4:2]
    

    5. iter 迭代 方法:

    用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__ 

    class Foo:
        def __init__(self,name,age):
            self.name = name
            self.age  = age
    
        def __iter__(self):   # iter方法
            return iter([11,22,33,44])  # 可迭代类型;
    
    obj = Foo("hailong",23)
    for item in obj:   
        print(item)
    

    for循环,例子二:

    class Foo:
        def __init__(self,name,age):
            self.name = name
            self.age  = age
    
        def __iter__(self):
            yield 1
            yield 2
    
    obj = Foo("hailong",23)
    for item in obj:
        print(item)
    

    6.  __module__ 和  __class__ 

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

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

    四. 面向对象的其它内容 

    1. isinstance 和 issubclass 内置变量;

    class Foo:
        pass
    
    class Func(Foo):
        pass
    
    obj = Foo()
    res = isinstance(obj,Foo) # obj  是 基于Foo类创建的,返回True;
    print(res)
    ret = issubclass(Func,Foo) # Func 类是 Foo类的一个子类,返回True;
    print(ret)
    

    2.  执行父类构造方法;

    如何执行,看实例:

    class Foo:
        def f1(self):
            print("Foo.f1")
    
    class Func(Foo):
        def f1(self):
            super(Func,self).f1()
            print('Func.f1')
    
    obj = Func()
    res = obj.f1() # obj 执行的了自己的f1方法也执行了父类里的f1方法,因为有super;
    

    这个方法应用于:当想要使用其它程序的功能或框架里的方法时,继承框架或功能的类方法,使用super就能使用框架的功能了;

    3. 有序字典:

    class Mydict(dict):
    
        def __init__(self):
            self.li = []
            super(Mydict,self).__init__()
    
        def __setitem__(self, key, value):
            self.li.append(key)
            super(Mydict,self).__setitem__(key,value)
    
        def __str__(self):
            temp_li = []
            for key in self.li:
                value = self.get(key)
                temp_li.append("'%s':%s" %(key,value))
            temp_str = "{" + ",".join(temp_li) + "}"
            return temp_str
    
    
    obj = Mydict()
    obj['k1'] = 123
    obj['k2'] = 456
    print(obj)
    

    代码解析:

      继承字典的类,将正常生成字典的key,添加到一个空列表,通过自定义类型对字典的生成过程重新定义,将无序存储的字典,写成一个列表,根据字符串拼接的方法,读取成有序的字典;

    五. 设计模式之单例模式

    用来创建单个实例,什么时候用?  不管获取多少个实例,他们的内存地址是一样的;

    class Foo:
        instance = None
        def __init__(self,name):
            self.name = name
    
        @classmethod
        def get_instance(cls):
            if cls.instance:
                return cls.instance
            else:
                obj = cls('hailong')
                cls.instance = obj
                return obj
    
    obj1 = Foo.get_instance()
    obj2 = Foo.get_instance() # 不管获取多少个实例,他们的内存地址是一样的;
    print(obj1,obj2) # 两个对象内存地址相同;
    

    六. 异常处理

    try --->except  try内容如果不报错,永远不会执行except的内容;

    1、异常基础

    在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户看见大黄页!!!

    try:
        pass
    except Exception,ex:
        pass

    需求:将用户输入的两个数字相加

    while True:
        num1 = input('input num1:')
        num2 = input('input num2:')
        try:
            num1 = int(num1)
            num2 = int(num2)
            result = num1 + num2
            try:
                print(result)
            except NameError as A:
                print(A)
        except Exception as E:
            print(E)
    

    2、异常种类

    python中的异常种类非常多,每个异常专门用于处理某一项异常!!!

    1) 常用异常:

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

    对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行。

    2)另一种结构的异常:

    try:
        # 主代码块
        pass
    except KeyError as ex:
        # 异常时,执行该块
        pass
    else:
        # 主代码块执行完,执行该块
        pass
    finally:
        # 无论异常与否,最终执行该块
        pass
    

    3) 主动抛出异常:

    try:
        raise Exception('错误了。。。')
    except Exception as ex:
        print(ex)
    

    4) 自定义异常:

    class WupeiqiException(Exception):
     
        def __init__(self, msg):
            self.message = msg
     
        def __str__(self):
            return self.message
     
    try:
        raise WupeiqiException('我的异常')
    except WupeiqiException as e:
        print(e)
    

    5)断言

    # assert 条件
     
    assert 1 == 1
     
    assert 1 == 2

    条件成立执行,不成立就不执行;

    ________________________________________________________END____________________________________________________

  • 相关阅读:
    我的友情链接
    我的友情链接
    我的友情链接
    我的友情链接
    我的友情链接
    我的友情链接
    我的友情链接
    以太坊设计与实现:数据结构与对象-账户
    以太坊设计与实现:数据结构与对象-创世区块与配置分析
    以太坊设计与实现:数据结构与对象-链配置
  • 原文地址:https://www.cnblogs.com/liuhailong-py-way/p/5624127.html
Copyright © 2020-2023  润新知