Python全栈开发之面向对象

发布时间:2019-08-05 14:59:52编辑:auto阅读(1227)

    No.1 概念

    面向对象的特点?

    注重对象和指责,不同的对象承担各自的指责

    更加适合对复杂的需求变化,专门应对复杂项目开发,提供固定的套路

    面向对象强调的是谁来做,面向过程强调的如何做

    什么是类

    类是对一群具有相同特征或者行为的事物统称,是抽象的,不能直接使用,特征被称为属性,行为被称为方法,类就是一个模板

    什么是对象

    对象是由类创建出来的一个具体存在,可以直接使用,通过哪个类创建出来的实例,就拥有哪个类中定义的特征和行为

    类和对象的关系

    类是模板,对象是根据类这个模板创建出来的,先有类,再有对象

    类只有一个,对象有多个

    类中定义的方法属性都会存在对象中,不多不少

    不同的对象之间的属性不尽相同

    No.2 类的创建

    方法名 类型 作用
    new 方法 通过类()创建对象时,向内存申请空间,并将对象引用传递给init
    init 方法 对象初始化时,会调用此方法
    del 方法 对象被销毁时,会调用此方法
    str 方法 返回对象的描述信息
    class Cat:
        """这是一个猫类"""
    
        def eat(self):
            print("小猫爱吃鱼")
    
        def drink(self):
            print("小猫在喝水")
    
    tom = Cat()
    tom.drink()
    tom.eat()

    对象中的self参数

    在类封装的方法内部,self就表示当前调用方法的对象自己
    调用方法时,不需要传递self参数
    在方法内部可以通过self.访问对象的属性
    也可以通过self.调用其他的对象方法
    class Cat:
        def __init(self,name)
            self.name = name
    
        def eat(self):
            print("%s 爱吃鱼" % self.name)
    
    tom = Cat('mimimi')
    tom.eat()

    No.3 封装

    封装是面向对象编程的一大特点

    面向对象将属性和方法封装到一个抽象的类中

    外部使用类创建对象,然后让对象调用方法

    对象方法的细节都被定义到类的内部

    No.4 继承

    DFS(深度优先算法):

    class E:
        def say(self):
            print('E')
    class D:
        pass
    class C(E):
        pass
    class B(D):
        pass
    class A(B,C):
        pass
    a = A()
    a.say()
    # 查找顺序 A->B->D->C->E

    BFS(广度优先算法):

    class E:
        def say(self):
            print('E')
    class D:
        pass
    class C(E):
        pass
    class B(D):
        pass
    class A(B,C):
        pass
    a = A()
    a.say()
    # 查找顺序 A->B->C->D->E

    C3(算法):

    class F:
        def say(self):
            print('F')
    class E(F):
        pass
    class D(F):
        pass
    class C(E):
        pass
    class B(D):
        pass
    class A(B,C):
        pass
    a = A()
    a.say()
    print(A.__mro__) # (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.F'>, <class 'object'>)
    # 查找顺序 A->B-?>D-C->E-F

    No.5 多态

    Python中不支持多态,也不用支持多态,Python是一种多态语言,崇尚鸭子类型,鸭子类型的概念来自于:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子,Python不会检查类型是不是鸭子,只要它拥有鸭子的特征,就可以被正确的调用

    class Duck:
        def speak(self):
            print('嘎嘎嘎...')
    class Dog:
        def speak(self):
            print('汪汪汪...')
    class Cat:
        def speak(self):
            print('喵喵喵...')
    animal = []
    animal.append(Duck)
    animal.append(Dog)
    animal.append(Cat)
    for i in animal:
        i().speak()
    # 嘎嘎嘎...
    # 汪汪汪...
    # 喵喵喵...

    No.6 类方法、静态方法、实例方法

    实例方法第一个参数必须是self,通过实例方法来传递实例的属性和方法,只能同实例来调用,静态方法使@staticmethod装饰器来定义,参数随意,静态方法是一个独立的函数,它仅仅依托于类的命名空间,不会涉及到类是属性和方法的作,静态方法因为没有参数绑定到该类所以仅仅提供函数功能,不能调用实例属性或静态属性,类方法使用@classsmethod来定义,第一个参数必须是cls,通过它传递类的属性和方法,类方法只能调用静态属性

    class Data():
        def __init__(self,year,month,day):
            self.year = year
            self.month = month
            self.day = day
        @staticmethod
        def static_method(date_str):
            year,month,day = tuple(date_str.split('-'))
            return Data(int(year),int(month),int(day))
        @classmethod
        def class_method(cls,date_str):
            year, month, day = tuple(date_str.split('-'))
            return cls(int(year), int(month), int(day))
        def object_method(self):
            print(self.year,self.month,self.day,sep='-')
    if __name__ == '__main__':
        date = Data(2018,9,15)
        date.object_method() # 2018-9-15
        date = Data.class_method('2018-9-16')
        date.object_method() # 2018-9-16
        date = Data.static_method("2018-9-17")
        date.object_method() # 2018-9-17

    No.7 类变量和实例变量

    类变量,可以通过类调用,也可以通过实例调用,在内存中之存在一份

    实例变量,只能通过实例调用,每个对象都有一份

    class Person:
        country = "中国"
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
    p1 = Person('kernel',18)
    print(p1.name) # kernel
    print(p1.age) # 18
    print(p1.country) # 中国
    print(Person.country) # 中国
    p1.country = "美国" # 当通过对象修改类变量时,将会在该对象创建一个和类变量同名的变量,类变量依然不变
    print(p1.country) # 美国
    print(Person.country) # 中国
    p2 = Person('alex',38)
    print(p2.name) # alex
    print(p2.age) # 38
    print(p2.country) # 中国

    No.8 私有属性和数据封装

    class User:
        def __init__(self,name,age):
            self.name = name
            self.__age = age
        def get_age(self):
            print(self.__age)
        def set_age(self,age):
            self.__age = age
    if __name__ == '__main__':
        u = User('kernel',18)
        # print(u.__age) # AttributeError: 'User' object has no attribute '__age' 好吧,私有属性不让我访问,但是真的无法访问吗
        print(u._User__age) # 但这又是什么鬼呢?当然我们不建议这么干
        u.set_age(19) 
        u._User__age=20 # 当然,设置也可以这样
        u.get_age() # 20

    No.9 单例模式

    new方法

    使用类名()创建对象,首先会调用new方法为对象分配空间,它的主要作用就是在内存中为对象分配空间和返回对象的引用,Python解释器得到对象的引用后,将引用传递给init

    让类创建的对象,在系统中只有唯一的一个实例

    定义一个类属性,初始值是None,用于记录单例对象的引用

    重写new方法

    如果类属性是None,调用方法申请空间,并在类属性中记录

    返回类属性中纪录的对象引用

    class MusicPlayer(object):
        instance = None # 记录第一个被创建对象的引用
        init_flag = False # 记录是否执行过初始化动作
    
        def __new__(cls, *args, **kwargs):
            if cls.instance is None:#  判断类属性是否是空对象
                cls.instance = super().__new__(cls)  #  调用父类的方法,为第一个对象分配空间
            return cls.instance # 返回类属性保存的对象引用
    
        def __init__(self):
            if not MusicPlayer.init_flag:
                MusicPlayer.init_flag = True
    
    player1 = MusicPlayer() # <__main__.MusicPlayer object at 0x0000017C297F99E8>
    print(player1)
    player2 = MusicPlayer() # <__main__.MusicPlayer object at 0x0000017C297F99E8>
    print(player2)

关键字