Python第八课----面向对象

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python第八课----面向对象相关的知识,希望对你有一定的参考价值。

一、面向对象

    1、封装:

        1、组装:将数据和操作(即属性和方法)组装到一起

        2、隐藏数据:对外只暴露一些接口,通过接口访问对象

    2、继承:

        1、多复用,继承的便不用自己写了

        2、多继承少修改,OCP-----减少冗余,增加复用

    3、多态:

        python不太需要了解

二、Python的类

    1、定义:

        1、必须使用class关键字

        2、类名必须是大驼峰

        3、类定义完成后就产生了一个类对象,绑定到了ClassName上

    

    class MyClass: # 定义一个类

        """A example class"""

        x = ‘abc‘ # 类属性

        def foo(self): # 类方法,self自带

            return ‘My Class‘

    print(MyClass.x)

    print(MyClass.foo)

    print(MyClass.__doc__)

三、类对象及类属性

    1、类对象,类的定义就会生成一个类对象

    2、类的属性,类定义中的变量和类中定义的方法都是类的属性

    3、类变量,x是MyClass的变量

        MyClass中,x和foo以及__doc__都是类的属性

        foo是method方法对象,不是普通的function,它必须至少一个参数,第一个必须是self。

        self纸袋当前实例本身

    4、实例化:a = MyClass( )

    5、__init__方法

        Python类实例化后,会自动调用__init__方法,这个方法第一个参数必须是self

        MyClass( )实际上调用的是__init__(self)方法,可以不定义,如果没有会在实例化后隐式调用

        作用:对实例进行初始化

        class MyClass:

            def __init__(self):

                print(‘init‘)

        a = MyClass() # 这个就会调用__init__

        初始化函数可以多个参数,第一个位置必须给self        

        class Person:

            def __init__(self,name,age):

                self.name = name

                self.age = age

            def showage(self):

                print(‘{} is {}‘.format(self.name,self.age))

        tom = Person(‘Tom‘,20) # 实例化

        jerry = Person(‘Jerry‘,25)

        print(tom.name,jerry.age)

        jerry.age += 1

        print(jerry.age)

        jerry.showage() # 调用方法

    __init__()方法不能有返回值,也就是只能是None

  6、实例对象instance

    类实例化后一定会获得一个对象,就是一个实例对象,tom,jerry都是Person的实例

    __init__方法的第一参数self就是指代某一个实例 

    class MyClass:

    def __init__(self):

    print(‘self in init = {}‘.format(id(self)))

    c = MyClass()

    print(‘c = {}‘.format(id(c)))--------->实例化会把c送到self的位置

  7、实例变量和类变量    

    class Person:

        age = 3

        def __init__(self,name):

            self.name = name

    tom = Person(‘Tom‘)

    jerry = Person(‘Jerry‘)

    print(tom.name,tom.age)

    print(jerry.name,jerry.age)

    print(Person.age)

    Person.age = 30

    print(Person.age,tom.age,jerry.age)

    实例变量是每一个实例自己的变量,是自己独有,类变量是类的变量,是类的所有实例共享的属性和方法

  8、

特殊含义

含义

__name__

对象名

__class__

对象的类型

__dict__

对象的属性字典

__qualname__

类的限定名

    举例:    

    class Person:

        age = 3

        def __init__(self,name):

            self.name = name

    print(Person.__class__)

    print(sorted(Person.__dict__.items()),end=\n\n)

    tom = Person(‘Tom‘)

    print(tom.__class__)

    print(tom.__dict__,end=\n)

    print(tom.__class__.__name__)

    print(tom.__class__.__dict__)

    是类的,就是这个类所有实例的,其实例都可以访问,是实例的,就是这个实例自己的,通过类访问不到。

    类变量是属于类的变量,这个类的实例可以共享

    实例可以动态给自己增加一个属性。实例的.__dict__[变量名]和实例.变量名都可以访问到

    实例的同名变量,就是实例自己的,会覆盖类的同名变量,但类的变量不变    

    class Person:

        age = 3

        height = 170

        def __init__(self,name,age=18):

            self.name = name

            self.age = age

    tom = Person(‘Tom‘)

    jerry = Person(‘Jerry‘,20)

    Person.age = 30

    print(Person.age,tom.age,jerry.age)

    print(Person.height,tom.height,jerry.height)

    tom.height += 10

    print(Person.height,tom.height,jerry.height)

    Person.height += 15

    print(Person.height,tom.height,jerry.height)

    Person.weight = 70

    print(Person.weight,tom.weight,jerry.weight)

    print(tom.__dict__[‘height‘])

    print(tom.__dict__[‘weight‘])

  9、实例属性的查找顺序

    tom.__dict__---->tom.__class__---->Person.__dict__

    类变量使用全大写来命名

  10、装饰一个类 

    def add_name(name):

        def wrapper(clz):

            clz.NAME = name

            return clz

        return wrapper

    @add_name(‘Tom‘)   # add_name = add_name(‘Tom‘)(Person)

    class Person:

        AGE = 3

    print(Person.NAME)

  11、类方法

        

    class Person:

        @classmethod     ----->装饰器,自带的,写法如下

        def class_method(cls):---->必须至少有一个参数,第一个默认cls,即类对象自身

            cls.HEIGHT = 170

    Person.class_method()----->需要运行一下,才能写进去

    print(Person.__dict__[‘HEIGHT‘])

    cls不能调用类的实例,因为cls是class_method的

  12、静态方法:   

    class Person:

        @classmethod

        def class_method(cls):

            cls.HEIGHT = 170

        @staticmethod

        def static_method():------>静态方法

            print(Person.HEIGHT)

    Person.class_method()

    Person.static_method()

    print(Person.__dict__)

13、方法的调用    

    class Person:

        def normal_method():

            print(‘normal‘)

        def method(self):

            print("{}‘s method".format(self))

        @classmethod

        def class_method(cls):

            print(‘class = {0.__name__}.({0})‘.format(cls))

            cls.HEIGHT = 170

        @staticmethod

        def static_method():

            print(Person.HEIGHT)

    print(1,Person.normal_method())

    # print(2,Person.method()) 这个不行

    print(3,Person.class_method())

    print(4,Person.static_method())

    print(Person.__dict__)

    tom = Person()

    # print(1,tom.normal_method()) 这个不行,不能给参数

    print(2,tom.method())

    print(3,tom.class_method()) # 可以,但是还是Person

    print(4,tom.static_method())

    类几乎可以调用所有内部定义的方法,但是调用普通方法会报错,因为第一个参数必须是类的实例

    实例也几乎可以调用所有的方法,普通函数的调用一般不会出现,不允许这么定义

    总结:

        类除了普通方法,都可以调用,普通方法需要对象的实例作为第一参数

        实例可以调用所有类中定义的方法(包括类方法,静态方法),普通方法传入实例自身,静态和类方法,需要找到实例的类

四、访问控制

    1、私有属性Private  

        class Person:

            def __init__(self,name,age=18):

                self.name = name

                self.age = age

            def growup(self,i=1):

                if i > 0 and i < 150:

                    self.age += i

        p1 = Person(‘Tom‘)

        p1.growup(20) # 正常范围

        print(p1.age)

        p1.age = 160 # 超过范围,还突破了if逻辑

        print(p1.age)

    私有属性方法:使用双下划线开头的属性名,就是私有属性

        

        class Person:

        def __init__(self,name,age=18):

            self.name = name

            self.__age = age

        def growup(self,i=1):

            if 0 < i < 150:

                self.__age += i

        p1 = Person(‘Tom‘)

        p1.growup(20)

        print(p1.__age) # 这句不能访问,因为__把它隐藏了

        print(p1._Person__age) # 不过依然可以访问,只是约定不访问

    访问方式:新建一个函数,直接内部返回定义的__age,外部实例调用这个函数即可 

        class Person:

        def __init__(self,name,age=18):

            self.name = name

            self.__age = age

        def growup(self,i=1):

            if 0 < i < 150:

                self.__age += i

        def getage(self):

            return self.__age

        p1 = Person(‘tom‘)

        print(p1.getage())

        p1.growup(20)

        print(p1.getage())

    2、保护变量

        在变量名前使用一个下划线,成为保护变量,就是个约定  

            class Person:

            def __init__(self,name,age=18):

                self.name = name

                self._age = age

            tom = Person(‘Tom‘)

            print(tom._age)

            print(tom.__dict__)

    3、私有方法    

        class Person:

            def __init__(self,name,age=18):

                self.name = name

                self._age = age

            def _getname(self): # 保护变量

                return self.name

            def __getage(self): # 私有变量

                return self._age

        tom = Person(‘Tom‘)

        print(tom._getname()) # 下划线只是约定保护,没什么卵用

        # print(tom.__getage()) # 无此属性

        print(tom.__dict__)

        print(tom.__class__.__dict__)

        print(tom._Person__getage())

五、补丁:可以通过修改或者替换类的成员。使用者调用的方式没有改变,但是类提供的功能可能已经变了

    猴子补丁,在运行时,动态替换属性,慎用

    test代码:

        class Person:

            def get_score(self):

                ret = {‘English‘:80,‘Chinese‘:99,‘History‘:90}

                return ret

    test1代码:

        def get_score(self):

            return dict(name=self.__class__.__name__,English=10,Chinese=20,History=30)

    test2代码:

        from test import Person   ---->导入Person

        from test1 import get_score  ---->导入修改模块

        def monkeypatch4Person():    ---->定义补丁函数

            Person.get_score = get_score  ---->将原需要修改的地方替换成现在的函数

        monkeypatch4Person()        ---->运行一下

        if __name__=="__main__":

            print(Person().get_score())   ---->测试结果

六:属性装饰器

    一般设计是:将实例的属性保护起来,不让外部访问,外部使用getter读取和setter设置信息

    原理:    

    class Person:

        def __init__(self,name,age=18):

            self.name = name

            self.__age = age   ---->私有起来

        def age(self):

            return self.__age  ---->外部读取实例属性信息

        def set_age(self,age):

            self.__age = age   ---->外部修改实例属性

    tom = Person(‘Tom‘)

    print(tom.age())

    tom.set_age(20)

    print(tom.age())

    实际应用方法;

    property装饰器:后面跟的函数名就是以后的属性名,它就是getter,这个必须有,有了就是只读    

    setter装饰器:与函数名同名,且接受两个参数,第一个self,第二个要修改的值,有了它,可写

    deleter装饰器:可以删除属性,很少用

    class Person:

        def __init__(self,name,age=18):

            self.name = name

            self.__age = age ---->定义一个私有属性

        @property   ---->装饰器私有属性

        def age(self): ---->定义函数读取属性

            return self.__age

        @age.setter

        def age(self,age): ---->定义函数修改属性

            self.__age = age

        @age.deleter 

        def age(self):   ---->定义函数删除属性

            del self.__age

    tom = Person(‘Tom‘)

    print(tom.age)

    tom.age = 20

    print(tom.age)

    # del tom.age

    # print(tom.age)

    其他写法:    

    class Person:

        def __init__(self,name,age=18):

            self.name = name

            self.__age = age

        def getage(self):

            return self.__age

        def setage(self,age):

            self.__age = age

        def delage(self):

            del self.__age

    age = property(getage,setage,delage,‘age property‘)--->这句写上后面可以直接.age

    tom = Person(‘Tom‘)

    print(tom.age)

    tom.age = 20

    print(tom.age)

    del tom.age

    或者;

    class Person:

        def __init__(self,name,age=18):

            self.name = name

            self.__age = age

        age = property(lambda self:self.__age)

    tom = Person(‘Tom‘)

    print(tom.age)

七、对象的销毁:

    类中可以定义__del__方法,成为析构函数(方法)

    作用:销毁类的实例的时候调用,以释放占用的资源

    由于python实现了垃圾回收机制,但不能确定何时执行,有必要时,使用del语句删除实例,手动调用   

    class Person:

        def __init__(self,name,age=18):

            self.name = name

            self.__age = age

        def __del__(self):

            print(‘del‘)

    tom = Person(‘Tom‘)

    del tom

    print(tom.__dict__)

八、类的继承

    1、通过继承,不需要写代码就可以继承父类的属性和方法

    class Animal:

        def __init__(self,name):

            self._name = name

        def shout(self):

            print(‘{} shout‘.format(self.__class__.__name__))

        @property

        def name(self):

            return self._name

        a = Animal(‘monster‘)

        a.shout()

    class Cat(Animal):

        pass

    cat = Cat(‘garfield‘)

    cat.shout()

    print(cat.name)

    class Dog(Animal):

        pass

    dog = Dog(‘ahuang‘)

    dog.shout()

    print(dog.name)

    2、特殊属性和方法

特殊属性和方法

含义

示例

__base__

类的基类


__bases__

类的基类元组


__mro__

显示方法查找顺序,基类的元组


mro()

同上

int.mro()

__subclasses__()

类的子类列表

int.subclasses__()

    3、继承中的访问控制    

    class Animal:

        __COUNT = 0

        HEIGHT = 0

        def __init__(self,age,weight,height):

            self.__COUNT += 1

            self.age = age

            self.__weight = weight

            self.HEIGHT = height

        def eat(self):

            print(‘{} eat‘.format(self.__class__.__name__))

        def __getweight(self):

            print(self.__weight)

        @classmethod

        def showcount1(cls):

            print(cls.__COUNT)

        @classmethod

        def __showcount2(cls):

            print(cls.__COUNT)

    class Cat(Animal):

        NAME = ‘CAT‘

    c = Cat(3,5,15)

    c.eat()

    print(c.HEIGHT)

    c.showcount1() # 类方法,实例无法调用,相当于类调用

    print(c.NAME)

    print(‘{}‘.format(Animal.__dict__))

    print(‘{}‘.format(Cat.__dict__))

    print(c.__dict__)

    print(c.__class__.mro())

    从父类继承,自己没有的,就可以到父类中找

    私有的都是不可以访问的,本质上是改了名

    4、方法的重写、覆盖override    

    class Animal:

        def shout(self):

            print(‘Animal shout‘)

    class Cat(Animal):

        def shout(self):

            print(‘miao‘)

        def shout(self):

            print(super())

            print(super(Cat,self))

            super().shout()

    a = Animal()

    a.shout()

    c = Cat()

    c.shout()

    print(a.__dict__)

    print(c.__dict__)

    print(Animal.__dict__)

    print(Cat.__dict__)

    覆盖自身也是可以的

    5、继承中的初始化    

    class Animal:

        def __init__(self,age):

            print(‘Animal init‘)

            self.age = age

        def show(self):

            print(self.age)

    class Cat(Animal):

        def __init__(self,age,weight):

            super().__init__(age)

            print(‘Cat init‘)

            self.age = age + 1

            self.weight = weight

    c = Cat(10,5)

    c.show()

九、多继承

    1、python3都是新式类,继承子object,新式类可以使用super

    2、多继承:OCP原则,多继承,少修改,增强基类,实现多态

    3、多态:在面向对象中,父类、子类通过继承练习在一起,如果一套方法,可以实现不同表现,就是多态

    4、一个类继承自多个类就是多继承,它将具有多个类的特征

    5、python使用MRO(method,resolution)







    

    

    


以上是关于Python第八课----面向对象的主要内容,如果未能解决你的问题,请参考以下文章

Python第十八课(面向对象基础)

Python之路第八篇:Python基础(24)——面向对象进阶

第八章:Python基础の面向对象(下集)

python3第八天(面向对象)

第八篇 python 面向对象编程

第八篇:python基础_8 面向对象与网络编程