• python3之面向对象


    1、面向对象术语

    • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
    • 类属性(类变量):类属性在整个实例化的对象中是公用的。类属性定义在类中且在函数体之外。类变量通常不作为实例变量使用。
    • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
    • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
    • 实例变量:定义在方法中的变量,只作用于当前实例的类。
    • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系。
    • 实例化:创建一个类的实例,类的具体对象。
    • 方法:类中定义的函数。
    • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

    2、类定义

    Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。

    对象可以包含任意数量和类型的数据。

    class test(object):   #定义一个类,在3.5中必须指定基类object
        i = 123       #类变量
        def func(self):   #类方法
            print('第一个类')
            return 'hell python'
    
    s = test()     #通过类实例化对象
    str = s.func()   #对象调用类方法
    print(test.i)   #通过类名调用类变量
    print(str)    #类返回值
    
    #output
    第一个类
    123
    hell python

    类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性和方法;实例化类后可以使用其属性,也可以动态的为实例对象添加属性而不影响类对象。

    可以使用点(.)来访问对象的属性,也可以使用函数的方式来访问属性:

    class A(object):
        def __init__(self,x):
            self.x = x
        def static_func(y=5):
            print(y)
    
    
    d = A(10)    #类实例化对象
    print(getattr(d,'x'))  #getattr访问对象的属性
    print(hasattr(d,'x'))  #hasattr检查对象属性是否存在
    print(setattr(d,'y','zhang'))   #设置对象的属性,如果属性不存在则创建新属性
    print(d.y)  #打印实例对象属性值
    delattr(d,'y')   #defattr删除对象属性
    print(hasattr(d,'x'))
    
    #output
    10
    True
    None
    zhang
    True

    python3内置类属性:

    __dict__:类的属性(包含一个字典,由类的数据属性组成)

    __doc__:类的文档字符串

    __name__:类名

    __module__:类定义所在的模块(类的全名是‘__main__.className’,如果类位于一个导入模块mymod中,那么className.__module__等于mymod)

    __bases__:类的所有父类构成元素(包含了以上所有父类组成的元组)

    class myclass(object):
        class_n = 'foo'
        def __init__(self,x,y,z):
            self.x = x
            self.y = y
            self.z = z
        def func_class(self):
            print('out:',self.x,self.y,self.z)
    
    t = myclass('10','20','50')
    t.func_class()   #调用实例方法
    
    print('__dict__:',myclass.__dict__)   #返回类的属性
    print('__dict__:',t.__dict__)   #返回实例属性
    print('__name__:',myclass.__name__)  #返回类名
    print('__doc__:',myclass.__doc__)   
    print('__module__:',myclass.__module__)  #返回类属在的模块
    print('__mro__:',myclass.__mro__)   
    print('__bases__:',myclass.__bases__)  #返回类对象
    
    
    #output
    out: 10 20 50
    __dict__: {'__init__': <function myclass.__init__ at 0x0000004249F0F378>, '__doc__': None, 'func_class': <function myclass.func_class at 0x0000004249F0F400>, 'class_n': 'foo', '__dict__': <attribute '__dict__' of 'myclass' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'myclass' objects>}
    __dict__: {'x': '10', 'z': '50', 'y': '20'}
    __name__: myclass
    __doc__: None
    __module__: __main__
    __mro__: (<class '__main__.myclass'>, <class 'object'>)
    __bases__: (<class 'object'>,)

    类的专有方法:

    • __init__ 构造函数,在生成对象时调用

    • __del__ 析构函数,释放对象时使用

    • __repr__ 打印,转换

    • __setitem__按照索引赋值

    • __getitem__按照索引获取值

    • __len__获得长度

    • __cmp__比较运算

    • __call__函数调用

    • __add__加运算

    • __sub__减运算

    • __mul__乘运算

    • __div__除运算

    • __mod__求余运算

    • __pow__乘方

    __init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法,类定义了__init__()方法后,类的实例化操作会自动调用__init__()方法,__init__()可以由参数,会传递到类的实例化操作上。

    self代表类的实例,而非类本身,在类的内部,使用def关键字来定义一个方法,与一般函数定义不同,类方法必须包含self,且为第一个参数,self代表的是类的实例。

    class test(object):
        def __init__(self,name,age,salary):  #初始化类属性
            self.name = name
            self.age = age
            self.salary = salary   #实例化对象会将类初始化到实例对象上
    
        def buygo(self):
            print('%s的工资是%s元' %(self.name,self.salary))  #调用类属性
    
    #通过类实例化对象
    zhansan = test('zhansan',20,8888)
    lisi = test('lisi',22,6000)
    #调用类方法
    zhansan.buygo()
    lisi.buygo()
    
    
    #output:
    #zhansan的工资是8888元
    #lisi的工资是6000元
    class test1(object):
        a = 10
        b = 20
        def get(self):
            print('取幂:',self.a.__pow__(self.b))
            print('求余数:',self.b.__mod__(self.a))
            print('乘:',self.b.__mul__(self.a))
            print('减:',self.b.__sub__(self.a))
            print('加:',self.b.__add__(self.a))
            print('输出:',self.b.__repr__())
    
    d = test1()
    d.get()
    
    #output
    取幂: 100000000000000000000
    求余数: 0
    乘: 200
    减: 10
    加: 30
    输出: 20

    实例方法,类方法,静态方法,类属性,实例属性:

    #实例方法,就是类的实例能够使用的方法
    class myclass(object):
        def __init__(self,name):
            self.name = name
        def instancefunc(self):
            print('调用实例方法%s'%self.name)
    
    
    if __name__ == "__main__":
        inst = myclass('zhangsan')   #通过类创建实例
        inst.instancefunc()   #实例使用实例方法
        myclass.instancefunc(inst)  #类使用实例方法,需要传递实例参数
    #类方法是将类本身作为对象进行操作的方法,类方法使用@classmethod装
    #饰器定义,其第一个参数是类,约定为cls,也可以自己定义,类对象和实例
    #都可以调用类方法,类方法只能调用类属性,不能调用实例属性。
    
    class A(object):
        number = 10   #定义类属性
        def __init__(self,name):   #初始化类属性
            self.name = name
        def car(self):   #定义实例方法
            print('实例方法:%s'%self.name)
        @classmethod   #定义类方法
        def cat(cls):  
            print('类方法:%s'%cls.number)  #此处不能调用类属性name,只能调用类属性number
    
    d = A('sb')
    d.car()   #实例调用实例方法
    d.cat()  #实例调用类方法
    A.cat()  #类调用类方法
    
    #output
    实例方法:sb
    类方法:10
    类方法:10
    #静态方法是一种普通函数,就位于类定义的命名空间中,它不会对任何实例类
    #型进行操作。使用装饰器@staticmethod定义静态方法。类对象和实例都可
    #以调用静态方法,静态方法不能调用类属性和实例属性,但可以调用传参。
    
    class A(object):
        number = 10
        def __init__(self,name):
            self.name = name
        def car(self):
            print('实例方法:%s'%self.name)
        @staticmethod   #定义静态方法
        def cat(x,y):    #定义调用传参
            print('静态方法:%s'%(x*y))
    
    d = A('sb')   #实例化类
    d.car()   #实例方法
    d.cat(5,4)   #实例调用静态方法
    A.cat(6,3)   #类调用静态方法
    
    #output
    实例方法:sb
    静态方法:20
    静态方法:18
    #类属性与实例属性在实例方法,类方法,静态方法中的调用关系
    class A(object):
        number = 10   #定义类属性
        def __init__(self,name):
            self.name = name   #实例属性
        def car(self):  #实例方法可以调用类属性和实例属性
            print('实例方法:%s[%s]'%(self.name,self.number))
        @classmethod
        def cae(cls):   #类方法只能调用类属性
            print('类方法:%s'%cls.number)
    
        @staticmethod
        def cat(x,y):   #静态方法不能调用类属性和实例属性
            print('静态方法:%s'%(x*y))
    
    d = A('sb')
    d.car()
    A.car(d)
    d.cae()  #实例调用方法
    A.cae()  #类调用方法
    d.cat(5,4)
    A.cat(6,3)
    
    #output
    实例方法:sb[10]
    实例方法:sb[10]
    类方法:10
    类方法:10
    静态方法:20
    静态方法:18

    3、类的封装

    封装是面向对象的特征之一,是对象和类概念的主要特性。

    封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

    python通过变量名命名来区分属性和方法的访问权限,默认权限相当于c++和java中的public

    类的私有属性: __private_attrs:两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时self.__private_attrs

    类的私有方法:__private_method:两个下划线开头,声明该方法为私有方法,不能在类地外部调用。在类的内部调用 self.__private_methods

    class myclass(object):
        def __init__(self,name,age):  #构造方法,根据类创建对象时自动执行
            self.name = name
            self.age = age
        def func(self):
            print('%s今年%s'%(self.name,self.age))
    
    #根据类创建对象,会自动执行类的__init__方法
    obj1 = myclass('zs',18)  #会将zs和18分别封装到类的self的name和age属性中
    obj2 = myclass('ls',20)
    
    print(obj1.name,obj1.age) #直接调用obj1对象的属性
    print(obj2.name,obj2.age)
    
    obj1.func() #默认会将obj1传递给self参数,即:obj1.func(obj1),所以此方法的内部self=obj1,self.name是zs
    obj2.func()
    
    #output
    zs 18
    ls 20
    zs今年18
    ls今年20
    class fater(object):
        __name = '私有属性'
        age = "公有属性"
        def func(self):
            print(self.age)
            print(self.__name)
        def __foo(self):   #定义私有方法
            print(self.__name)
    class son(fater):
        def show(self):
            print(fater.age)
            #print(fater.__name)
    
    print(fater.age)    
    print('----------------')
    
    obj1 = fater()
    obj1.func()
    print('----------------')
    #obj1.__foo()   #直接调用会报错,只有通过"_类名__方法"的形式调用
    obj1._fater__foo()  #调用私有方法
    print(obj1.age)
    #print(obj1.__name)  #直接调用会报错,通过“_类名__属性”方法调用
    print(obj1._fater__name)  #调用私有属性
    
    print('-------son----')
    obj2 = son()
    obj2.show()  #调用父类属性
    obj2.func()
    obj2.__foo()  #调用父类方法错误
    obj2._fater__foo()  #正确调用父类方法
    
    #output
    公有属性
    ----------------
    func: 公有属性
    func: 私有属性
    ----------------
    __foo: 私有属性
    公有属性
    私有属性
    -------son----
    show: 公有属性
    func: 公有属性
    func: 私有属性
    __foo: 私有属性

    4、类继承

    继承是面向对象的重要特征之一,继承是两个类或者多个类之间的父子关系,子类继承了父类的所有公有实例变量和方法。
    继承实现了代码的重用。重用已经存在的数据和行为,减少代码的重新编写。
    python在类名后用一对圆括号表示继承关系,括号中的类表示父类或基类
    #经典类和新式类的区别:当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。
    class old:   #经典类写法
        pass
    
    
    class new(object):  #新式类写法
        pass

    在python中类继承的特点:

    1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。使用super().__init__()或parentClassName.__init__()

    2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数

    3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。

    如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。

    class test(object):   #定义父类
        def __init__(self,name,age,salary):
            self.name = name
            self.age = age
            self.salary = salary
    
        def buygo(self):
            print('%s[%s]岁就有%s元的工资了' %(self.name,self.age,self.salary))
    
    class test_student(test):   #调用父类
        def __init__(self,name,age,salary,nb):  
            test.__init__(self,name,age,salary)  #重写父类构造方法
            self.nb = nb
        def buygo(self):   #覆写类方法
            print('%s[%s]岁就有%s元的工资了,很%s' %(self.name,self.age,self.salary,self.nb))
    
    
    #通过类实例化对象
    zhansan = test_student('zhansan',20,8888,'牛逼哦')
    lisi = test_student('lisi',22,6000,'得瑟吧')
    
    zhansan.buygo()
    lisi.buygo()
    
    #output:
    zhansan[20]岁就有8888元的工资了,很牛逼哦
    lisi[22]岁就有6000元的工资了,很得瑟吧

    如果父类中的方法名相同于子类中的方法名,子类方法将覆盖父类方法。

    多继承的优先级顺序是:在新式类中是从左往右查找,找到即停止;而经典类是深度查找的从左到右如:A(B,C),B(D),那么顺序是A->B->D->C

    5、多态

    多态依赖于继承,多态的作用,就是为了类在继承和派生的时候,保证继承类中实例的某个属性或方法的调用,实现了接口的重用。class A(object):    def __init__(self):

            self.name = 'ZHANGSAN'
        def show(self):
            print('A.show:',self.name)
    class B(A):
        def show(self):
            print('show_b:',self.name)
    class C(A):
        def show(self):
            print('show_c:',self.name)
    
    def func(obj):   #定义函数,传递对象
        obj.show()   #通过类实例对象调用类下的方法
    
    A_obj = A()
    B_obj = B()
    C_obj = C()
    
    func(A_obj)
    func(B_obj)
    func(C_obj)

    #output

    A.show: ZHANGSAN
    show_b: ZHANGSAN
    show_c: ZHANGSAN

     

    6、总结

    • 面向对象的知识总计如下:
    • 面向对象时一个编程方式,此编程方式的实现是基于对类和对象的使用
    • 类是一个模版,模版中包装了多个‘函数’供使用
    • 对象根据模块创建实例,实例可以调用被包装在类中的函数
    • 继承实现了多个类直接的方法属性调用,减少代码的重用性
    • 多态在继承的基础上解决了方法调用的重用,而不被子类给覆盖。
    • 面向对象的三大特性:封装、继承和多态
  • 相关阅读:
    1 Groovy
    HDU
    伸展树整理
    HYSBZ
    markdown语法整理
    HDU
    【JZOJ3085】图的计数【数论】
    【JZOJ3085】图的计数【数论】
    【JZOJ3084】超级变变变【模拟】【规律】
    【JZOJ3084】超级变变变【模拟】【规律】
  • 原文地址:https://www.cnblogs.com/zhangxinqi/p/8081731.html
Copyright © 2020-2023  润新知