zoukankan      html  css  js  c++  java
  • python基础篇【第八篇】面向对象(下)

    一、 面向对象特性之多态:

      上一篇已经介绍了面向对象的三大特性的前两种(封装、继承),下面来说说第三种多态,在python中用不上,但在其他语言中很重要。

    多态的意思就是多种类型、多种形态,比如字符类型,数字,字典,列表等。在python中定义类或函数时不需要,指定是那种数据类型全都支持,但是在java、c#等其他语言中需要指定如下实例:

    def func(A arg)
                   print(arg)
              arg :参数必须是A 类型,或A类型的子类

    二、类成员:

      类成员分为三大类:字段、方法、属性

    1、字段

    在类中字段分为静态字段和普通字段

    普通字段(动态字段):存储在对象中,由对象调用

    静态字段:存储在类中,由类调用,在代码加载时,就已经创建了

    调用规则:

    1、一般情况下自己访问自己;

    2、普通字段,只能由对象访问

    3、静态字段用类访问,(万不得已的时候也可以用对象访问,不建议使用)

    两者区别如下:

    class Foo:
        CC = 123  # CC是静态字段,保存在类中
    
        def __init__(self):
            self.name = "tom"  # name 就是普通字段,保存在对象中

    实际调用如下:

    class Province:
        contry="中国" #静态字段
    
        def __init__(self,name):
            self.name=name   #普通字段
    
    sx=Province("河南")
    #静态调用 如 Province.contry
    #普通调用 如 sx.name
    print(Province.contry,sx.name)
    
    #显示结果
    中国 河南

    静态字段存储在类中, 只在内存中保存一份;

    普通字段存储在每个对象中,需要在每个对象中都保存一份

    应用场景:如果创建对象时,都要需要某一个相同的字段,可以把字段设置为静态字段,节省内存

    2、方法

    方法都属于类包括:

    静态方法:属于类,由类来调用执行,无默认参数,等同于函数。创建方式:  方法上边加个@staticmethod

    普通方法:由对象调用,至少需要一个self参数。执行普通方法时,self就是对象本身,自动将调用该方法的对象赋值给self

    类方法:是静态方法的一种特殊形式。由类调用,至少要有一个参数cls,值为类名。创建方式: @classmethod

    class Province:
        contry="中国"
    
        def __init__(self,name):   #普通方法
            self.name=name
    
        def show(self):
            print("普通方法")
    
        @classmethod
        def class_show(cls):     #类方法
            print(cls)
    
        @staticmethod
        def static_show():   #静态方法
            print("静态方法")
    
    sx=Province("河南")
    
    #普通方法调用
    sx.show()
    
    #类方法调用
    Province.class_show()
    
    #静态方法调用
    Province.static_show()
    
    
    
    #显示结果
    普通方法
    <class '__main__.Province'>    #是这个类名
    静态方法

    相同点:由于所有的方法都属于类, 所以在内存中存储只保存一份。

    不同点:由于各种方法的调用方式不同,调用方法时自动传入的参数不同。

    给上面字段一样,在对象中也是可以调用静态方法和类方法的。不到万不得已还是不要用,要遵循变成原则。

    3、属性

    属性就是普通方法的变种

    下面来看一下属性的定义:

    class Foo:
        
        def show(self):
            print("普通方法")
          
        @property   #定义属性
        def prop(self):
            pass
    
    #调用
    obj=Foo()
    obj.show()   #调用方法
    obj.prop    #调用属性

    注意:

    定义时,在普通方法的基础上添加@property装饰器;仅有一个参数self

    调用时,无需加括号

    还有一种属性的定义调用方法:

    class Foo():
    
        @property
        def price(self):
            print('查询')
    
        @price.setter
        def price(self, value):
            print('设置')
    
        @price.deleter
        def price(self):
            print('删除')
    
    # ############### 调用 ###############
    obj = Foo()
    
    obj.price          # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
    
    obj.price = 123    # 自动执行 @price.setter 修饰的 price 方法,并将  123 赋值给方法的参数
    
    del obj.price      # 自动执行 @price.deleter 修饰的 price 方法
    
    #执行结果
    查询
    设置
    删除

    三、类成员修饰符

    公有成员:就是在哪都能访问,

    私有成员,只有在类的内部才能放问,其他都不能访问,继承关系也不能

    定义私有成员:命名是前面是两个下划线,(特殊成员除外,例如:__init__、__call__、__dict__等)

    如下:

    class Foo:
        def __init__(self):
            self.name="公有字段"
            self.__fuck="私有字段"

    四、类的特殊成员

    1、__init__

    构造方法,通过类创建对象时,自动触发

    class Foo:
    
        def __init__(self,name):
            self.name = name # name 就是普通字段
            self.job="IT"
    
    obj=Foo("tom")   #自动执行类中的__init__方法
    print(obj.name)
    print(obj.job)
    
    #结果
    tom
    IT

    2、__doc__

      表示类的描述信息,就是注释

    class Foo:
        '''
        描述信息
        '''
        def __init__(self,name):
            self.name = name # name 就是普通字段
            self.job="IT"
    print(Foo.__doc__)
    
    #显示结果
       描述信息
        
    View Code

    3、__del__

      析构方法,用于对象在内存中垃圾回收时,自动触发执行

    4、__call__

      在对象后面加括号,执行

    对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

    class Foo:
    
        def __init__(self,name):
            self.name = name # name 就是普通字段
    
        def __call__(self, *args, **kwargs):
            print("执行call方法")
    obj=Foo("test")  #执行__init__方法
    obj()   #执行__call__方法
    View Code

    5、__module__、__class__

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

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

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    class Foo:
        '''
        这是类的描述信息, 由特殊成员 __doc__调用
        '''
        def __init__(self,name):
            self.name = name
            # print(self.name)
    
        def show_info(self):
            print(self.name)
    
    bin/modules.py内容
    bin/modules.py
    from bin import modules
    
    obj = modules.Foo('DBQ')
    print(obj.__module__)   # 查看当前操作的对象属于哪个模块
    
    print(obj.__class__)       #查看当前操作的对象的类是哪个
    
    
    #执行结果:
    bin.modules
    <class 'bin.modules.F1'>
    View Code

    6、__dict__

      获取对象或类中的所有成员

    class Foo:
        CC="test"
        def __init__(self,name):
            self.name = name # name 就是普通字段
    
    
    #获取类中的所有成员
    print(Foo.__dict__)
    
    #获取对象中的成员
    obj=Foo("tom")
    print(obj.__dict__)
    
    #显示结果
    {'__weakref__': <attribute '__weakref__' of 'Foo' objects>, 'CC': 'test', '__doc__': None, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Foo' objects>, '__init__': <function Foo.__init__ at 0x00000041DAED61E0>}
    {'name': 'tom'}
    View Code

    7、__str__

      如果一个类中定义了__str__方法,那么打印对象时,默认输出该方法的返回值

    class Foo:
        CC="test"
        def __init__(self,name):
            self.name = name # name 就是普通字段
    
        def __str__(self):
            return "hi tom"
    
    obj=Foo("tom")
    print(obj)
    
    #结果
    hi tom
    View Code

    8、__iter__

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

    class Foo():
    
        def __init__(self, sq):
            self.sq = sq
    
        def __iter__(self):
            return iter(self.sq)
    
    obj = Foo([11,22,33,44])
    
    for i in obj:
        print(i)
    View Code

    9、__getitem__、__setitem__、__deltiem__

    用于索引操作, 如字典。 分别表示获取、设置、删除数据。 

    class Foo():
        def __getitem__(self, item):
            print("执行get操作,调用__getitem__方法")
        def __setitem__(self, key, value):
            print("执行set操作,调用__setitem__方法")
        def __delitem__(self, key):
            print("执行del操作,调用__delitem__方法")
    
    obj=Foo()
    obj['a1']   #get操作,自动触发__getitem__方法
    obj["a1"]=[1,2,3,4,5] #set操作,自动调用__setitem__方法"
    del obj['a1']   #del操作,自动调用__delitem__方法
    
    #结果
    执行get操作,调用__getitem__方法
    执行set操作,调用__setitem__方法
    执行del操作,调用__delitem__方法
    View Code

    10、__getslice__、__setslice__、__delslice__

      用于分片操作

    class Foo(object):
     
        def __getslice__(self, i, j):
            print '__getslice__',i,j
     
        def __setslice__(self, i, j, sequence):
            print '__setslice__',i,j
     
        def __delslice__(self, i, j):
            print '__delslice__',i,j
     
    obj = Foo()
     
    obj[-1:1]                   # 自动触发执行 __getslice__
    obj[0:1] = [11,22,33,44]    # 自动触发执行 __setslice__
    del obj[0:2]                # 自动触发执行 __delslice__
    python2.7执行

    在python3中还是运用的__getitem__、__setitem__、__deltiem__

    class Foo():
    
        def __getslice__(self, i, j):
            print('__getslice__',i,j)
    
        def __setslice__(self, i, j, sequence):
            print('__setslice__',i,j)
    
        def __delslice__(self, i, j):
            print('__delslice__',i,j)
    
        def __getitem__(self, item):
            print("执行get操作,调用__getitem__方法")
        def __setitem__(self, key, value):
            print("执行set操作,调用__setitem__方法")
        def __delitem__(self, key):
            print("执行del操作,调用__delitem__方法")
    obj = Foo()
    
    obj[-1:1]                   # 自动触发执行 __getslice__
    obj[0:1] = [11,22,33,44]    # 自动触发执行 __setslice__
    del obj[0:2]                # 自动触发执行 __delslice__
    
    #结果
    执行get操作,调用__getitem__方法
    执行set操作,调用__setitem__方法
    执行del操作,调用__delitem__方法
    python3中

    11. __new__ 、 __metaclass__

    class F1:
        def __init__(self,name):
            self.name = name
    
        def show_info(self):
            print(self.name)
    
    obj = F1('tom')
    
    print(type(obj))
    
    print(type(F1))
    
    # #执行代码结果:
    # <class '__main__.F1'>      #表示 obj对象由 F1类实例化而来
    # <class 'type'>                  #表示 F1类由 type 类创建

    python中一切介对象,上述代码中obj是F1的一个对象,那么可以推理F1其实也是一个对象

    所以,obj对象时F1类的一个实例,F1类对象时type类的一个实例,F1类对象时通过type类构造方法创建

    创建方法有两种普通方法、特殊方法:

    普通方法:

    class F1:
        def __init__(self,name):
            self.name = name
    
        def show_info(self):
            print(self.name)

    特殊方法:

    def show_info(self):
        print('tom')
    
    F1 = type('F1',(object,),{'show_info':show_info})
    #第一个参数: 类名
    #第二个参数: 当前类的基类
    #第三个参数: 类成员
    
    obj = F1()
    obj.show_info()

    ==》 类 是由 type 类实例化产生

    那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?

    答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。

     五、面向对象其他相关知识

      1、isinstance(obj,cls)

     检查是否obj是否是类 cls 的对象

    判断一个对象是不是类创建的()实例,返回布尔值,继承的父类也为真

    class F1:
        pass
    
    class F2(F1):
        pass
    
    obj = F2()
    
    print(isinstance(obj,F1))    #查看是否是父类的实例, 为真
    print(isinstance(obj,F2))    #查看是否是F2类的实例, 为真

    2、issubclass(F1,F2)

    检查F1是否是F2的子类

    查看是否是某类的子类

    class F1:
        pass
    
    class F2(F1):
        pass
    
    obj = F2()
    
    print(issubclass(F2,F1))   #查看F2是否是F1的子类, 为真
    print(issubclass(F1,F2))   #查看F1是否是F2的子类, 为假

    3、 super 

    扩展别人的源码 ,尽量不在源码中修改

    class C1:
        def f1(self):
            print('C1.f1')
    
    class C2(C1):
        def f1(self):
            super(C2,self).f1()   #在执行C2代码之前,执行C1中的f1方法 也就是C2父类的f1方法
            print('C2.f1')
    
    obj = C2()
    obj.f1()
    
    #结果
    C1.f1
    C2.f1

    五、异常处理与捕获

    1、异常处理基础

    增加友好性,在程序出现bug中一般不会将错误信息显示给用户,而是显示一个页面

    while True:
    
        num = input('请输入你一个或多个整数: ').strip()
    
        try:
            num = int(num)
            print('你输入的数字是: %d'%num)
        except Exception:
            print('%s, 你输入的不是一个整数格式!'%Exception)
    
    
    # 如果输入的是一个整数类型,将返回输入的号码
    # 如果输入的是其他的类型,如字符串、浮点数等,会提示用户输入的不是一个整数格式!
    
    ####执行结果:
    请输入你一个或多个整数: 123
    你输入的数字是: 123
    请输入你一个或多个整数: a
    <class 'Exception'>, 你输入的不是一个整数格式!
    请输入你一个或多个整数: 1.
    <class 'Exception'>, 你输入

    2.异常处理

    捕获异常可以使用 try / except语句。try: 用来检测语句块中的错误,从而让 except中语句捕获的异常信息并处理。

    打开一个文件,往文件中写入内容,并且没有发生异常:

    复制代码
    try:
        f = open('test.txt','w')
        f.write('测试文件,用于测试异常捕获')
    except IOError:
        print('Error: 写入失败, 没有找到文件或者权限不足!')
    else:
        print('写入成功!')
        f.close()
    
    #执行结果:
    写入成功!
    
    #文件内容:
    Daniel-Mac:blog daniel$ cat test.txt &&echo
    测试文件,用于测试异常捕获
    复制代码

    修改文件的权限没有写,而后在打开文件,往文件中写入内容,查看异常:

    复制代码
    chmod -w test.txt 
    try:
        f = open('test.txt','w')
        f.write('测试文件,用于测试异常捕获')
    except IOError:
        print('Error: 写入失败, 没有找到文件或者权限不足!')
    else:
        print('写入成功!')
        f.close()
    
    #再次执行代码:
    Error: 写入失败, 没有找到文件或者权限不足!
    复制代码

     常用异常:

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

    实例:

    下标异常

    dic = ["tom", 'jerry']
    try:
        dic[10]
    except IndexError, e:    
        print e


    key异常

    dic = {'k1':'v1'}
    try:
        dic['k20']
    except KeyError, e:
        print e

    元素异常

    s1 = 'hello'
    try:
        int(s1)
    except ValueError, e:
        print e

    对于上述实例,异常类只能用来处理指定的异常情况,如果没有指定异常则无法处理。

    # 未捕获到异常,程序直接报错
     
    tt = 234
    try:
        str(tt)
    except IndexError,e:
        print e

    如果想通吃各种异常,python中也提供了一个万能异常Exception,就能捕获任意异常,目的是保证程序能正常运行

    tt = 234
    try:
        str(tt)
    except Exception,e:
        print e

    如果你还想要知道异常是什么,在那一块报错了,还有一个更周全的方案,如下:

    s1 = 'hello world'
    try:
        int(s1)
    except KeyError:
        print('Error: Key错误!')
    except IndexError:
        print('Error: 索引错误!')
    except ValueError:
        print('Error: 值错误!')
    except Exception:
        print('Error: 出错了!')
    else:
        print('你的值是: %s'%s1)

    六、设计模式,单实例

    例模式,顾名思义,也就是单个实例的意思。

    模式特点:保证类仅有一个实例,并提供一个访问它的全局访问点。

    class Singleton:
        __instance = None   #定义一个私有静态字段为初始值
    
        def __init__(self,name):
            self.name = name
    
        def show(self):
            print(self.name)
            return 'test_instance'
    
        @classmethod
        def get_instance(cls):
            if cls.__instance:  #如果字段内有值,直接返回字段值
                return cls.__instance
            else:                     
                obj = cls('DBQ')          #实例化
                cls.__instance = obj    #将对象赋值给字段
                return cls.__instance   #返回对象
    
    
    a = Singleton.get_instance()
    b = Singleton.get_instance()
    
    print(a)
    print(id(a))   #内存地址和b相同
    print()
    print(b)
    print(id(b))    #内存地址和a相同
    # 后面再来几个对象,也是一样的!
    
    #代码执行结果:
    <__main__.Singleton object at 0x101b769b0>
    
    <__main__.Singleton object at 0x101b769b0>
    单实例

    单例模式的存在主要是保证当前内存中存在单个实例,避免内存资源浪费。

  • 相关阅读:
    QT 双缓冲
    ubuntu 安装SVN客户端
    高并发linux内核网络参数调优
    c aes 解密
    qt 字符类型转换
    c++ ado 操作类
    Qt中将QString转换为char *或者相反
    c++ aes 加密 解密
    [转载]python编码转换遇到的非法字符的解决方法
    [转载] python异常如何全面捕获
  • 原文地址:https://www.cnblogs.com/tianjie0522/p/5634043.html
Copyright © 2011-2022 走看看