美文网首页Python进阶之路
python基础-09-面向对象、装饰器

python基础-09-面向对象、装饰器

作者: 162f127842fc | 来源:发表于2017-11-16 21:02 被阅读42次

    面向对象

    • 类概念
    • 类的定义
    • 类的实例化
    • 类和实例的属性
    • 类的私有变量
    • 数据封装
    • 继承
    • 多态
    • 多继承
    • 类的特殊方法
    • 装饰器
    • 类的装饰器
    1.面向对象(Object Oriented,OO)概念
        面向对象,是我们编程的一种思维。
        早期的计算机编程是基于面向过程的方法,例如实现算术运算1+1+2 = 4,通过设计一个算法就可以解决当时的问题。随着计算机技术的不断提高,计算机被用于解决越来越复杂的问题。通过面向对象的方式,将现实世界的事物抽象成对象,现实世界中的关系抽象成类、继承。通过面向对象的方法,更利于用人理解的方式,对复杂系统进行分析、设计与编程。同时也提高了系统的可维护性,可扩展性,可重用性。
        (就是使编程的思维,更接近与人的思维和认知)
    
    
    面向对象编程的关键,就是类的定义。
    类是对现实生活中一类具有共同特征的事物的抽象。
    
    2.类的定义
    基本形式:
        class ClassName(object):
            Statement
          
    1.class定义类的关键字
    2.ClassName类名,类名的每个单词的首字母大写(驼峰规则)。
    3.object是父类名,object是一切类的基类。在python3中如果继承类是基类可以省略不写。
    '''
    class Animal(object):
        pass
    '''
    
    '''
    重点:学会定义类,了解属性和方法,类的初始化和实例化。
    定义类时,这种方法可以使类对象实例按某种特定的模式生产出来。
    '''
    #类方法:
    
    后面的参数中第一个参数我们约定俗成的为self参数名,
    self代表的是在类实例化后这个实例对象本身。
    
    '''
    class Animal: 
        #构造方法,实例化对象,必须调用__init__
        #在初始化的时候,默认往构造方法,传入一个值
        #self是实例化对象本身
        def  __init__(self): 
            print("正在实例化一个对象")
        def test(self):#实例化对象调用方法,必须加上self
            print("aaa")
        def test1(self,b):#第一个参数默认是self参数,不需要传值
            print("方法;test1,self=%s"%(type(self)))
        def test2():#未加self参数,只能通过  Animal.test2()直接调用,实例化对象无法调用
            print("方法;test2")
    运行结果:
    >>> Animal().test1(1111)
    正在实例化一个对象
    方法;test1,self=<class '__main__.Animal'>
    '''
    '''
    class Animal:   #当我们没有写__init__(),默认调用我们父类的__init__
        def test(self):
            print("aaa")
    '''
    
    
    
    
    初始化函数除了有self这个参数表示实例对象本身之外,
    其他的参数的定义也遵循函数的必备参数和默认参数一样的原则,
    必备参数就是在实例化是一定要传入的参数,
    默认参数就是在定义时可以给这个参数一个初始值。没有函数名的函数
    
    
    3.类的实例化
     基本形式:实例对象名 = 类名(参数)
    
        在实例化的过程中,self代表的就是这个实例对象自己。
    
        实例化时会把类名后面接的参数传进去赋值给实例,
        这样传进去的参数就成为了这个实例对象的属性。
    
        实例化的过程遵循函数调用的原则。
        在实例化时也必须个数和顺序与定义时相同(使用关键字参数可以改变传参的顺序)。
        当初始化函数定义时使用了默认参数时,在实例化时默认参数可以不传参这时
        这个实例对象就会使用默认的属性,如果传了参数进去则会改变这参数值,
        使实例化对象的属性就为你传进来的这个参数。
    
        isinstance(实例名,类名)
        判断一个实例是不是这个类的实例。
    
    4.类和实例的属性
    
         类属性
                .类属性是可以直接通过“类名.属性名”来访问和修改。
                .类属性是这个类的所有实例对象所共有的属性,
                任意一个实例对象都可以访问并修改这个属性(私有隐藏除外)。
                .对类属性的修改,遵循基本数据类型的特性:列表可以直接修改,字符串不可以,
                所以当类属性是一个列表时,通过任意一个实例对象对其进行修改。
                但字符串类型的类属性不能通过实例对象对其进行修改。
                当实例对不可变对象进行修改之后,会查找实例的类属性,不会查找类的属性,同时类的属性不会边
            
            实例属性
                .在属性前面加了self标识的属性为实例的属性。
                .在定义的时候用的self加属性名字的形式,在查看实例的属性时
                就是通过实例的名称+‘.’+属性名来访问实例属性。
    '''
    class Aniaml:
        eye=2  #共有的属性
        def __init__(self,name,food):
            print("正在实例化")
            self.name=name #实例化属性
            self.food=food
        def getName(self):
            print(self.name)
    运行:
    >>> dog=Aniaml("大黄","骨头")
    实例化属性调用:
    >>> dog.name  #调用实例属性
    '大黄'
    类属性调用:
    >>>Aniaml.eye
    >>> dog.eye 
          '''
    
            一些说明:
                .一般,方法第一个参数被命名为self,,这仅仅是一个约定,
                self没有特殊含义,程序员遵循这个约定。
                .查看类中的属性和实例属性可以调用__dict__方法返回属性组成的字典。
                .Python中属性的获取是按照从下到上的顺序来查找属性
                .Python中的类和实例是两个完全独立的对象
                .Python中的属性设置是针对对象本身进行的
    
    5.类的私有属性和方法
    
            在Python中,通过单下划线”_”来实现模块级别的私有化,
           一般约定以单下划线”_”开头的变量、函数为模块私有的,
           也就是说”from moduleName import *”将不会引入以单下划线”_”开头的变量、函数
           '''
           import random #显示所有的方法,属性
           from random import *  #只显示
           '''
    
            对于Python中的类属性,可以通过双下划线”__”来实现一定程度的私有化。
            _”和” __”的使用 更多的是一种规范/约定,并没有真正达到限制的目的:
    
            “_”:以单下划线开头只能允许其本身与子类进行访问,(起到一个保护的作用)
            “__”:双下划线的表示的是私有类型的变量。这类属性在运行时属性名会加上单下划线和类名。
            “__foo__”:以双下划线开头和结尾的(__foo__)代表python里特殊方法专用的标识,如 __init__()
            '''
           class Aniaml:
        eye=2
        _age=3
        __leg=4
        def __init__(self,name,food):
            self.name=name
            self.food=food
        def getName(self):
            print(self.name)
      >>> dog._age   #单_会隐藏属性名称
      >>> dog._Aniaml__leg  #双_会隐藏属性名称,双_会修改属性的名称
           '''
    

    6.数据封装

        在类里面数据属性和行为函数的形式封装起来,
        访问时直接调用,不需知道类里面具体的实现方法。 比如,list.append
        封装:
        def test2():
               print("方法;test2")
    
    7.继承
    用法:
        .在定义类时,可以从已有的类继承,
        被继承的类称为基类(父类),新定义的类称为派生类(子类)。
        
        .在类中找不到调用的属性时就搜索基类,
         如果基类是从别的类派生而来,这个规则会递归的应用上去。
         反过来不行。
        
        .如果派生类中的属性与基类属性重名,那么派生类的属性会覆盖掉基类的属性。
         包括初始化函数。
        
        .派生类在初始化函数中需要继承和修改初始化过程,
         使用’类名+__init__(arg)’来实现继承和私有特性,也可以使用super()函数。
        
        issubclass(类名1,类名2)
        判断类1是否继承了类2
        
    作用:
        面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。
        继承完全可以理解成类之间的类型和子类型关系。
        
        子类在重写父类方法之后,如果要继承父类方法中的功能,要先调用父类的方法  class.fun(self)
    '''
    class Aniaml:
        eye=2
        _age=3
        __leg=4
        def __init__(self,name,food):
            self.name=name
            self.food=food
        def getName(self):
            print(self.name)
    
    class People(Aniaml):#继承
        __leg=2
        def __init__(self,name,food,sex):
            self.name=name
            self.food=food
            self.sex=sex
        def getSex(self):
            print(self.sex)
    '''
    
    

    8.多态

    当派生类重写了基类的方法时就实现了多态性。(子类重写父类方法)
    class Aniaml:
        eye=2
        _age=3
        __leg=4
        def __init__(self,name,food):
            self.name=name
            self.food=food
        def getName(self):
            print(self.name)
    
    class People(Aniaml):
        __leg=2
        def __init__(self,name,food,sex):
            self.name=name
            self.food=food
            self.sex=sex
        def getSex(self):
            print(self.sex)
        def speak(self):
            print("adsfsfd")
    
    class Chinese(People):#中国人 
        def speak(self):#中国文说你好
            print("你好"
    
    class America(People):#美国人
        def speak(self):#美国人说Hello
            print("Hello")
            
    class Thai(People):#泰国人
        def speak(self):#泰国人说萨瓦迪卡
            print("萨瓦迪卡")
    
    xiaomi=Chinese("小明","米饭","男")
    jack=America("jack","面包","男")
    lala=Thai("lala","香蕉","未知")
    
    9.多继承
    #当继承的类有同种方法的时候,只会继承前面一个的方法。调用父类方法super()
    class Base:
        def play(self):
            print("This is base")
    
    class A(Base):
        def play(self):
            print(type(self))
            print("This is a")
    class B(Base):
        def play(self):
            print("This is b")
    class C(A,B):
        def play(self):
            #A.play(self) #第一种调用父类的方法
            super().play()#第二种调用父类的方法,同super(C,self).play()
            #super(C,self).play()
            print("This is c")
    运行效果:
    <class '__main__.C'>
    This is a
    This is c
    #对象的扩展使用
    #C().__class__.mro()  查看对象的排序
    #C(B,A)   C->B->A->Base->object 针对C继承对象排序
    #C(A,B)   C->A->B->Base->object 针对C继承对象排序
    class C(B,A):
        def play(self):
            #super(A,self).play()  #调用base
            super(B,self).play()  #调用a
    >>> C().__class__.mro()  #C->B->A->Base->object 针对C继承对象排序
    [<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.Base'>, <class 'object'>]
    
    10.类的特殊方法
    千万不要把自己往死胡同里面逼,否则你会走火入魔
    '''
    class Rectangle:
        '''测试'''
        aaa=1
        def __init__(self,length,width):
            if isinstance(length,(int,float)) and isinstance(width,(int,float)):
                self.length=length
                self.width=width
            else:
                print("请输入int or float")
        def area(self):
            return self.length*self.width
        def __str__(self):
            return "这个长方形的面积%s"%self.area()
        def __repr__(self):
            return "长:%s 宽:%s"%(self.length,self.width)
        def __call__(self):
            print("这是一个Rectangle类,你要干嘛")
        def __add__(self,other):
            return self.area()+other.area()
        def __sub__(self,other):
            return self.area()-other.area()
    r=Rectangle(2,3)
    r1=Rectangle(2,3)
    r2=Rectangle(2,3)
    
    '''
    
    #类属性:
    __dict__     # 类的属性(包含一个字典,由类的数据属性组成)
    
    
    >>> r.__dict__
    {'length': 2, 'width': 3}
    >>> r.aaa=33
    >>> r.__dict__  
    #注意,共有属性,当不修改时,默认引用Rectangle
    #修改之后,才会出现再实例里面
    {'length': 2, 'width': 3, 'aaa': 33}
    
    __doc__     # 类的文档字符串
    >>> r.__doc__
    '测试'
    
    #类方法:(魔法方法) ,方法也是对象
        __init__    # 初始化
        __repr__    # 直接返回这个对象  repr() 函数就是调用对象的这个方法
        >>> r
        长:2 宽:3
    
        __str__     # print(obj) 如果类里面定义了__repr__,没有定义__str__ print(obj)也会返回__repr__的内容,或者说__repr__的优先级更高
        >>> print(r) #重写print方法了
        这个长方形的面积6
        "%s"%"ssss"  对应  __str__
        "%r"%"rrrr"  对应 __repr__
      
        __call__    # Obj() 使实例可被调用
        >>> r()
        这是一个Rectangle类,你要干嘛
        
    #运算符方法
        __add__(self,other)     #x+y
        >>> r1+r2
        12
    
        __sub__(self,other)     #x-y 
        __mul__(self,other)     #x*y  
        __mod__(self,other)     #x%y
        __iadd__(self,other)    #x+=y
        __isub__(self,other)    #x-=y 
        __radd__(self,other)    #y+x
        __rsub__(self,other)    #y-x 
        __imul__(self,other)    #x*=y 
        __imod__(self,other)    #x%=y 
        
    #和类有关的几个函数  
        delattr()        # 删除对象属性
        getattr()        # 得到某个属性值
        setattr()        # 给对象添加某个属性值
        hasattr()          # 判断对象object是否包含名为name的特性
        isinstance()      # 检查对象是否是类的对象,返回True或False
        issubclass()      # 检查一个类是否是另一个类的子类。返回True或False    
    
    11.装饰器
    装饰器(deco):
        装饰函数的参数是被装饰的函数对象,返回原函数对象装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象
        概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
    
    def  f1(func):
        print("f1 running")
        def f2(y):
            print("f2 running")
            return func(y)+1
        return f2
    @f1
    def  gun2(m):
        print("gun running")
        return m*m
    #运行结果
    f1 running
    >>> gun2(5)
    f2 running
    gun running
    26
    运行流程
    1.@f1->f1(gun2)->f2
    2.f2,等待调用
    3.gun2(2)->当参数5传入->f2(5)
    4.f2(5),开始运行->print("f2 running")->fun(y):func=gun2 y=5
    5.gun2(5) 开始运行->print("gun running")->25
    6.25+1=26
    
    #测试时间的装饰器
    import time  #不要纠结
    
    def run_time(func):
        def new_fun():
            t0 = time.time()
            print('star time: %s'%(time.strftime('%x',time.localtime())) )
            func()
            print('end time: %s'%(time.strftime('%x',time.localtime())) )
            print('run time: %s'%(time.time() - t0))
            
        return new_fun
    
    
    
    @run_time
    def test():
        for i in range(1,10):
            for j in range(1,i+1):
                print('%dx%d=%2s'%(j,i,i*j),end = ' ')
            print ()
    
    12.类装饰器
    '''
    class Rectangle:
        '''测试'''
        aaa=1
        def __init__(self,length,width):
            if isinstance(length,(int,float)) and isinstance(width,(int,float)):
                self.length=length
                self.width=width
            else:
                print("请输入int or float")
        @property #可以把方法当属性使用
        def area(self):
            return self.length*self.width
        @staticmethod #把方法变成静态方法
        def func():
            print("可以调用")
        @classmethod  #把实例化对象转换成类
        def show(self):
            print(self)
            print("show fun")
      
    >>> Rectangle(2,3).area
    6
    '''
    
    @property 
        装饰过的函数返回的不再是一个函数,而是一个property对象
        装饰过后的方法不再是可调用的对象,可以看做数据属性直接访问。
    
    
    @staticmethod #(静态方法)
        把没有参数的函数装饰过后变成可被实例调用的函数,      
        函数定义时是没有参数的,可以不接收参数
    
    @classmethod (类方法)
        把装饰过的方法变成一个classmethod类对象,既能能被类调用又能被实例调用。
        注意参数是cls代表这个类本身。而是用实例的方法只能被实例调用。     
            
    一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。
    而使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。
    这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁
    '''
    #类装饰器
    
    '''
    class Test_Class():
        def __init__(self,func):
            self.func=func
        def __call__(self):
            print("类")
            return self.func
    @Test_Class
    def fun_test():
        print("这只是一个测试")
    运行:
    >>> fun_test()
    类
    <function fun_test at 0x033081E0>
    >>> fun_test()()
    类
    这只是一个测试
    #python自带的3个,类的内置装饰器
    
    

    相关文章

      网友评论

        本文标题:python基础-09-面向对象、装饰器

        本文链接:https://www.haomeiwen.com/subject/nqvrvxtx.html