zoukankan      html  css  js  c++  java
  • python基础之类(面向对象编程)

    一、引入


    1.1 概述

      python支持函数式编程也支持面向对象编程

    1.2 什么是面向对象?

      下面以一个例子来说明面向对象的问题

            class Bar:--函数变为对象
                def foo(self,name,age,gender,content):
                    print(name,age,gender,content)            
            obj=Bar()  
            obj.foo(小明,10岁,男,上山去砍柴)

      面向对象定义:

        class class_name:

          def def_name(self,arg):

            print(arg)

            return 1

        中间人=类名()    ret=中间人.方法名()       print(ret)为1,谁调用这个函数这个值变返回给谁 

      由以上可知想执行函数要通过类对象间接访问 

        原函数执行:函数名(参数)

        现函数执行:面向对象:要间接访问里面的内容 o=Bar() ----对象,实例,o.foo()

        对比函数与对象:创建一个类,加载时在内存里有一个类的内存,在这个内存里再分个内存做方法,在另一个内存里创建一个中间人指向这个类内存,

                它只能找到这个类里的方法

            class Bar:
                def foo(self,arg):
                    print(self,arg)
                z1 = Bar()//z1是指向Bar这个类的地址
                print(z1)//是一个对象的内存地址
                z1.foo(111)---self就是z1的内存地址
                z2 = Bar()---也会传给self,不同的对象
                
            中间人对象:中间人内部也能放东西,引用其地址加变量等
                  class Bar:
                      def foo(self,arg):
                          print(self,self.name,self.age,arg)
                  z=Bar()---对象,在对象里添加值如下
                  z.name='alex'---注这里中间人里加东西不是中间人调用类里面的方法
                  z.age=18
                  print(z.foo(111))----中间人调用方法,同时方法也能取中间人放在里面的东西并打印,二者是相互的
            上个实例:--封装
                class Bar:
                    def add(self,content):
                        print(self.name,self.age,content)---可以拿不同对象里的值
                    def delete(self,content):
                        print(self.name,self.age,content)   
                    def update(self,content):
                        print(self.name,self.age,content)
                obj=Bar()
                obj.name='小明'
                obj.age=10
                obj.add(上山去砍柴)
                obj.delete(开车去东北)------这时相同的值就不用改了,被装在了中间人里,只会那边会变的就行,不用相同的值重复打
            构造方法:
                特殊作用:
                   在 obj=类名()----做了二个事情:第一:创建对象  第二:通过对象执行类中的一个特殊方法,特殊方法用_init_(self)来定义的函数
               class Bar:
                    def _init_(self):
                        print('123')
                    def add(self,content):
                        print(self.name,self.age,content)
               z=Bar()
               print(z)---会打印二个一个是内存地址一个是123,也可以在_init_函数里加参数,做初始化
                    def _init_(self,name,age):-----这个方法就叫构造方法                    
                        self.n=name
                        self.a=age
                        self.b=1                    
                    def add(self,content):
                        print(self.n,content)                    
                    z=Bar('alex',18)---除了给他值alex与18还有一个默认值1,类里的参数传给构造函数初始化数据
                    z.add('home')

    二、面向对象三大特性


      类里的方法创建如下:

        构造方法,__init__(self,arg)

          obj = 类('a1')----字段

        普通方法

          obj = 类(‘xxx’)

          obj.普通方法名()    

    2.1 面向对象三大特性之一:封装

            class Bar:
                def __init__(self, n,a):
                self.name = n
                self.age = a
                self.xue = 'o'
        
                b1 = Bar('alex', 123)
    
                b2 = Bar('eric', 456)

      适用场景:如果多个函数中有一些相同参数时,转换成面向对象,封装到_init_

            class DataBaseHelper:
    
            def __init__(self, ip, port, username, pwd):--连数据库需要的
                self.ip = ip
                self.port = port
                self.username = username
                self.pwd = pwd
    
            def add(self,content):
                # 利用self中封装的用户名、密码等   链接数据
                print('content')
                # 关闭数据链接
    
            def delete(self,content):
                # 利用self中封装的用户名、密码等   链接数据
                print('content')
                # 关闭数据链接
    
            def update(self,content):
                # 利用self中封装的用户名、密码等   链接数据
                print('content')
                # 关闭数据链接
        
            def get(self,content):
                # 利用self中封装的用户名、密码等   链接数据
                print('content')
                # 关闭数据链接
    
                s1 = DataBaseHelper('1.1.1.1',3306, 'alex', 'sb')

    2.2 面向对象三大特性之二:继承

      1. 继承:可多层继承

            class 父类:
                pass
            
            class 子类(父类):
                pass
            例:class father:----父类,基类
                    def 篮球(self):
                       pass
                class son(father):---son就是子类,也叫派生类,这时父类的所有def子类都可以执行
                    def 抽烟(self):
                       pass
            

      2.重写:如何重写父类的方法?

        父类里的某些方法,子类自己定义一个与其名字一样的,那只能执行子类的

      3.self永远是执行改方法的调用者

      4.如何子类与父类的二个相同方法都要执行?

            class father:----父类,基类
                def 篮球(self):
                   pass
    
            class son(father):---son就是子类,也叫派生类,这时父类的所有def子类都可以执行
                def 抽烟(self):
                   pass    
                def 篮球(self):
                   super(son,self).篮球()---也可以是父类的其它方法,子类执行父类的方法
                   pass                       
            法1:super(子类, self).父类中的方法(...)
            法2:父类名.父类中的方法(self,...)

      5.python支持多继承 

            a. 左侧优先
               class son(father,father1):------如果二个都是一个方法刚左侧优先,里面都是有方法f1
               
               obj=son()
               obj.f1()---则执行左边
            b. 一条道走到黑
               如上father的f1是继承它的父类的就一条道走到黑
            c. 同一个根时,根最后执行
               二条路最后都指向同一个父类,先左边走到了倒数第二个就走第二条路,最后执行根

      6.应用:新做的功能想使用开源的方法就可以使用继承

               开放的:
                    class father:
                        def 篮球(self):
                           pass
               新的功能:
                    class son(father):
                         def 其它(self):
                           pass

    2.3 面向对象三大特性之三:多态

            # Java:必须要指定变量类型
                string v = 'alex'
            
                def func(string arg):---这个变量必须指定类型
                    print(arg)
                
                func('alex')
                func(123)
        
            # Python :是多态的不用指定
                v = 'alex'
            
                def func(arg):
                    print(arg)
                    
                
                func(1)
                func('alex')

    三、面向对象的高级用法


    3.1 类成员分类

            类成员:
            # 字段
                - 普通字段,保存在对象中,执行只能通过对象访问
                - 静态字段,保存在类中,执行可以通过对象访问 也可以通过类访问,在方法外类内定义的字段
    
            # 方法
                - 普通方法,保存在类中,由对象来调用,self=》对象
                   例:
                      class Foo:
                         def bar(self):
                          print('bar')
                      obj = Foo()---先找到self
                      obj.bar()----对象调用
                      
                      Foo.bar(obj)----对象当参数调用,这些都是普通方法                
                - 静态方法,保存在类中,由类直接调用
                   例:
                      class Foo:
                         def bar(self):----普通方法
                          print('bar')
                         @staticmethod---它下面的方法就是静态方法了,就不用传对象了,可以直接类调用就行
                         def str():
                           print('123')
                    Foo.str()--就用调用str方法了,就是类自己的所有固定值了而不在是对象的特有的值了,所有对象都有共同的值   
                   
                -   类方法,保存在类中,由类直接调用,cls=》当前类,类直接调的是类,函数的参数是类
                  例:
                  class Foo:
                        def bar(self):----普通方法
                          print('bar')
                        @classmethod
                        def classmd(cls):---cls是类名不是对象
                            print('classmd')
                  Foo.classmd()---加载的是类
    
             应用场景:
                普通方法:如果对象中需要保存一些值,执行某功能时,需要使用对象中的值
                静态方法:不需要任何对象中的值

    3.2 方法的其它属性装饰器使用

            @property   //一个装饰器,叫属性,作用是把普通方法的调用变为字段的调用             
                用于执行obj.per,如下
                class Foo:
                  @property
                  def per(self):
                      return 1
                  obj=Foo()
                  r=obj.per----这个对象调用不带(),相当于字段的调用,想赋值怎么办
            @per.setter  //这些方法要自己实现
                用于执行obj.per=123赋值,用于赋值
                class Foo:
                  def per(self,val):
                      print(val)
                   obj=Foo()
                   obj.per=123
            @per.deleter
                用于删除:---函数做什么自己写不是真的用于删除什么的               
                   def per(self):
                       print(666)
                    obj=Foo()
                    del obj.per
                所以不同的调用格式就执行不同的对应的函数

      以上功能的作用:

            比如分页:
               li = []---空列表
               for i in range(100):
                   li.append(i)---列表加100个值
               while True:
                   p = input('请输入要查看的页码:')
                   p = int(p)--字符变为数字
                   start = (p-1)*10
                   end = p*10
                   print(li[start:end])
            升级把start end做为一个组件
                 class Pergination:
                     def _init_(self,current_page)
                         try:--异常处理
                            p=int(current_page)
                         except Exception as e:
                           p=1
                         
                         self.page=int(current_page)
                    @property
                    def start(self):
                        val = (self.page-1)*10
                        return val
                    @property
                    def end(self):
                      val=self.page*10
                      return val
                这样再调用时print(li[obj.start:obj.end])

    四、 类的其它知识点


    4.1 类成员修饰符

      字段的权限:  

        1.公有成员

        2.私有成员:外部不能直接访问

            普通字段私有化
                class Foo:
                    def __init__(self,name,age):
                        self.name = name
                        self.age = age
                        self.__age = age加上二个下划线,这个就访问不了了,但能在内部访问
                    def show(self):
                        return self.__age----这时就可以访问的到了
    
                obj = Foo()
                obj.name
                #obj.age
                obj.__age---这个就访问不了,这个就是私有成员
            静态字段私有化
                class Foo:
                    __v='123'
                    def __init__(self):
                        pass
                    def show(self):
                        return Foo.__v
                ret=Foo().show()
            普通方法的公私有
                class Foo:
                    def __f1(self):
                        return 123
    
                    def f2(self):    
                        r = self.__f1()
                        return r
    
                obj = Foo()
                ret = obj.f2()
                print(ret)

    4.2 特殊成员认识

      1. __call__:对象后加()是执行特殊成员__call__的=Foo()()

            class Foo:
                def __init__(self):
                    print('init')
    
                def __call__(self, *args, **kwargs):
                    print('call')
    
            # obj = Foo()
            # obj()-----对象后加()是执行特殊成员__call__的=Foo()() 
            

      2.数据类型相互转化

        __int__    __str__

      

            # s = "123"-----转为字符型相当于 s = str('123')
    
            # i = int(s)----字符转为数值
            # print(i,type(i))
            
            那函数等能转化吗?
               class Foo:
    
                    def __init__(self)://构造方法
                        pass
    
                    def __int__(self):
                        return 1111
    
                    def __str__(self):
                        return 'alex'
    
              obj = Foo()
              print(obj, type(obj))
    
             # int,对象,自动执行对象的 __int__方法,并将返回值赋值给int对象
                r = int(obj)---int里加的对象会自动运行_int_方法,对象进行类型转化,这时对象的值不为地址了而是str方法定义的值
                print(r)
                i = str(obj)---str里加的对象会自动运行_str_方法,对象进行类型转化,这时对象的值不为地址了而是str方法定义的值
                print(i)-----直接返回的是类对象的值不是地址了

      3. 对象相加要执行的特殊方法

            class Foo:
    
                def __init__(self, name,age):
                    self.name = name
                    self.age = age
    
                def __add__(self, other):
                    # self = obj1      封装了(alex,19)
                    # other = obj2     封装了(eric,66)
                    # return self.age + other.age----定义r返回的结果
                    #return Foo('tt',99)
                    return Foo(obj1.name, other.age)
    
                def __del__(self):
                    print('析构方法') # 对象被销毁()时,自动执行
    
            obj1 = Foo('alex', 19)
            obj2 = Foo('eirc', 66)
    
            r = obj1 + obj2
            # 两个对象相加时,自动执行第一个对象的的 __add__方法,并且将第二个对象当作参数传递进入
            print(r,type(r))

      4.析构方法 ---对象被销毁()时,自动执行

        def __del__(self):---析构方法

      5. *对象转为字典的形式

                __dict__:# 将对象中封装的所有内容通过字典的形式返回,而非一个地址
                    class Foo:
                        def __init__(self, name,age):
                            self.name = name
                            self.age = age
                            self.n = 123
    
                    # obj = Foo('alex', 18)
    
                    # d = obj.__dict__----对象的成员通过字典显示出来
                    # print(d)
                     ['name':alex,'age':18]
    
                    # ret = Foo.__dict__----类成员通过字典显示出来
                    # print(ret)

      6. *索引 __getitem__ __setitem__   __delitem__

            # li = [11,22,33,44]
            # li = list([11,22,33,44])
    
            # li[3]----调用展示的方法
    
            # li[3] = 666---调用修改的方法
    
            # del li[2]----删除方法
            class Foo:
    
                def __init__(self, name,age):
                    self.name = name
                    self.age = age
    
                def __getitem__(self, item):
                    # return item+10
                    # 如果item是基本类型:int,str,索引获取
                    # slice对象的话,切片
                    if type(item) == slice:
                        print('调用这希望内部做切片处理')
                    else:
                        print(item.start)
                        print(item.stop)
                        print(item.step)
                        print('调用这希望内部做索引处理')
    
                def __setitem__(self, key, value):
                    print(key,value)
    
                def __delitem__(self, key):
                    print(key)
            li = Foo('alex', 18)
            r= li[8] # 自动执行li对象的类中的 __getitem__方法,8当作参数传递给item,后加个[]
            print(r)
            r=li[1:2:3]---切片,也用的是__getitem__方法,所以要在方法里判断,在python3里是这样的
            li[100] = "asdf"--自动执行li对象的类中的 __setitem__方法,key是100,asdf是value
    
            del li[999]---自动执行li对象的类中的 __delitem__方法

      7. __iter__:变为可迭代对象

            class Foo:
    
                def __init__(self, name,age):
                    self.name = name
                    self.age = age
    
                def __iter__(self):
                    return iter([11,22,33])
            li = Foo('alex', 18)//这虽然是个地址,但它里面包含的有数据,只是返回的值地址,类方法可定义对象返回什么样的值
            for i in li:------这个调用就会执行__iter__的方法,对象循环,是可迭代对象,这个是类里有这个方法时才能用的
                print(i)
                
                # 如果类中有 __iter__ 方法,对象=》可迭代对象
                # 对象.__iter__() 的返回值: 迭代器
                # for 循环,若后是迭代器,直接执行next,一个一个的拿
                # for 循环,若后是可迭代对象,先调用对象.__iter__()变为迭代器后再进行next
                # 1、执行li对象的类F类中的 __iter__方法,并获取其返回值
                # 2、循环上一步中返回的对象

    4.3 metaclass:类的祖宗

      1.Python中一切事物都是对象

      2. 类也是对象

            class Foo:
                pass
    
    
            obj = Foo()
            # obj是对象,Foo类
            # Foo类也是一个对象,它是type的对象

    例: class Foo: def func(self): print(12) 以上这个代码解释器拿到后会进行如下处理: def funtion(self): print(12) Foo=type('Foo',(object,),{'func':funtion})----object:超级类所有的类都继承这个类。声明了一个类

      3. 类都是type类的对象   type(..)

        “对象”都是以类的对象 类()

            问题:type创建类这个对象时执行的是__init__,这个是由C实现的,所以看不了,如果类不想用type创建如何做?
                class MyType(type):----MyType做为type的子类,所以先用MyType的__init__
                    def __init__(self,*args, **kwargs):
                        # self=Foo,这时还没有obj所以它是Foo
                        print(123)
                        pass
    
                    def __call__(self, *args, **kwargs):
                        # self=Foo
                        obj = self.__new__()
                        self.__init__----Foo.__init__
    
            python2:class Foo(object):
                    __metaclass__ =MyType
       
            python3:class Foo(object,metaclass=MyType):------定义Foo用MyType这个类来创建不再用type了
                    def __init__(self):
                        pass
    
                    def __new__(cls, *args, **kwargs):
                        return '对象'----这个对象就给r了,它是obj
    
                    def func(self):
                        print('hello wupeiqi')
                1.结果是123
                2.obj = Foo()----执行MyType的__call__方法,这里会调用__new__--在这里创建生成的obj

     

    4.4 异常处理

      1. 捕捉异常:try...except Exception as e:

              try: 
                 #代码块,逻辑
                 inp=input("请输入序号:")----输入数字就走这个输入是字母就走下一个,都不会报错
                 i=int("inp")----出现错误后try下面的代码不会执行直接跳到下面的选择里
                 
              except Exception as e:
                 #如果try里面出错就会创建一个Exception对象,对象中封装错误信息
                 #上述代码块如果出错,自动执行当前块的内容,这样代码就不会报错了
                 print(e)---打应错误信息
                 i = 1
                 print(i)
              注:Exception是所有错误信息都能扑捉封装
                  IndexError:扑捉的是索引错误
                  ValueError:扑捉的是值的错误
                  IOError:IO错误
             else:
                 print(12)---不出错就执行
             finally:
                print(34)---出不出错都执行
                try:
                    li=[11,22]
                    li[999]----这个报错IndexError能扑到
                    int(se)----这个报错就扑不到程序就会报错
                except IndexError as e:
                    print(e)

      2.主动抛出异常

            try:
                # int('asdf')
                # 主动出发异常
                # raise Exception('不过了...')--这是关键字段,这步自己报错,下面来捕捉,Exception报的是报错内容,这是个函数,可以自己定义函数
            except Exception as e:
                print(e)
                
            例:
                def db():
                    # return True
                    return False
    
                def index():
                    try:
                        r = input(">>")
                        int(r)
                        result = db()
                        if not result:
                            r = open('log','a')
                            r.write('数据库处理错误')
                            # 打开文件,记录日志
                            #raise Exception('数据库处理错误')
                        except Exception as e:
                            str_error = str(e)
                            print(str_error)
                            r = open('log', 'a')
                            r.write(str_error)
                            # 打开文件,记录日志
                index()

      3.自定义异常类,可自调用使用

            class OldBoyError(Exception):
    
                def __init__(self, msg):
                    self.message = msg
    
                def __str__(self)://类生成对象返回的结果 
                    return self.message
    
              # obj = OldBoyError('xxx')
              # print(obj)
              try:
                  raise OldBoyError('我错了...')---自定义函数报错
              except OldBoyError as e:
              
              print(e)# e对象的__str__()方法,获取返回

      4.断言

        # assert 条件,断言,用于强制用户服从,不服从就报错,可扑捉,一般不扑捉

        # assert 1==2------必须成立程序才能执行,否则一条都不会执行

        # print(456)

    4.5 反射

      1.通过字符串的形式操作对象中的成员(用特定方法拿类或函数里的成员不用调用)

            class Foo:
                def __init__(self, name,age):
                self.name = name
                self.age = age
    
                def show(self):
                    return  "%s-%s " %(self.name,self.age)
                def __int__(self):
                    return 123
                def __str__(self):
                    return 'uuu'
            obj = Foo('alex', 18)---对象
    
            r = int(obj) # 这个对象的数值是r = 123
            u = str(obj)
            b = 'name'
            obj.__dict__['name']=obj.__dict__[b]-----拿出alex,这种方法比较麻烦为减化封闭一个方法如下
            
            更好的写法:去什么东西里面获取什么内容?
                 getatter(obj,'name')
    
            总写法:反射,通过字符串的形式操作对象中的成员
            # getattr---去什么东西里面获取什么内容,从对象里获取某字段,从某模块里获取某函数等
            # hasattr---检测对象里是否有某成员
            # setattr---修改对象里某成员的值
            # delattr---删除对象里的某值
            # 通过字符串的形式操作对象中的成员
    
            # func = getattr(obj, 'show')
            # print(func)
            # r = func()
            # print(r)
    
            # print(hasattr(obj, 'name'))
            # obj.k1
            # setattr(obj, 'k1', 'v1')
            # print(obj.k1)
            # obj.name
            # delattr(obj, 'name')---删除对象某值
            # obj.name
    
            # 去什么东西里面获取什么内容
            # inp = input('>>>')----只能输入name  age
            # v = getattr(obj, inp)
            # print(v)----输入name得到的是alex的结果

      2.实例

            class Foo:
    
                stat = '123'
    
                def __init__(self, name,age):
                    self.name = name
                    self.age = age
    
            # 通过字符串的形式操作对象中的成员
            r = getattr(Foo, 'stat')
            print(r)
            
            操作模块也可以
                import s2
    
    
                # r1 = s2.NAME
                # print(r1)
                # r2 = s2.func()
                # print(r2)
    
                r1 = getattr(s2, 'NAME')----NAME是变量
                print(r1)
    
                r2 = getattr(s2, 'func')---拿到func的地址,func是函数
                result = r2()
                print(result)
    
                cls = getattr(s2, 'Foo')--Foo是类
                print(cls)
                obj = cls()
                print(obj)
                print(obj.name)
                
            一个网页,不同的按钮进入不同的网页,URL也不同,若第一个按钮对应模块s2.py 第二个对应s3.py    
                在s1中写入
                import s2
                import s3
                inp = input('请输入要查看的URL:')
                if hasattr(s2, inp):---是否有这个值
                    func = getattr(s2, inp)得到s2的inp的值
                    result = func()
                    print(result)
                else:
                    print('404')  

    4.6 单例模式:用于使用同一份实例

            class Foo:
            #    def __init__(self, name,age):
            #        self.name = name
            #        self.age = age
    
            # obj = Foo() # obj对象,obj也成为Foo类的 实例,(实例化)
            # obj1 = Foo()
            # obj2 = Foo()
            # obj3 = Foo()
            这个例子跟单例有什么关系,这上面是四个实例,用到四个内存
            
            单例,用于使用同一份实例(对象)
                class Foo:
                    def __init__(self, name,age):
                        self.name = name
                        self.age = age
    
                    def show(self):
                        print(self.name,self.age)
    
                v = None
    
                while True:
                    if v:
                        v.show()----只用这一个单例,只用一个实例
                    else:
                        v = Foo('alex', 123)
                        v.show()
            改良
                class Foo:
    
                    __v = None
    
                    @classmethod
                    def get_instance(cls):---这个函数里的类
                        if cls.__v:----类时的私有静态字段
                            return cls.__v
                        else:
                            cls.__v = Foo()
                            return cls.__v
    
                # 不要在使用 类()来创建一个对象
                obj1 = Foo.get_instance()----创建对象,用类方法创建对象
                print(obj1)
                obj2 = Foo.get_instance()
                print(obj2)
                obj3 = Foo.get_instance()
                print(obj3)

      

         

     

      

     

      

            

          

  • 相关阅读:
    《Codeforces Round #696 (Div. 2)》
    从Java源码角度聊设计模式之工厂模式
    HashMap死循环【基于JDK1.7】情景重现与分析(带示意图)
    Java应用级别的线程中断—interrupt&isInterrupted&interrupted的区别
    Java队列学习笔记(2)---DelayQueue
    Java队列学习笔记(1)---AbstractQueue&PriorityQueue
    junit测试用例从src/test/resources下的txt文件读取多行数据并随机选择一行
    (Ant编程) Ienumerable类型、枚举器 和自定义的 linq
    如何 给select 下拉框 设定默认值
    分页sql
  • 原文地址:https://www.cnblogs.com/Dana-xiong/p/14316776.html
Copyright © 2011-2022 走看看