# 面向对象 """ 面向对象特点 1.封装: 依据功能需求将某些属性与方法封装到一个类中 2.继承: 实现代码的重复调用,相同的功能调用不需要重复编写 3.多态: 不同的对象调用相同的类方法,产生不同的执行结果 面向对象的基本知识点 类: 描述具有相同的属性和方法的对象的集合,具有抽象性,不能直接使用,主要职责是创建对象 对象:通过类定义的,具有属性与方法的具体实例,可以使用 方法:类中定义的函数 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。 局部变量:定义在方法中的变量,只作用于当前实例的类。 实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。 实例化:创建一个类的实例,类的具体对象。 在程序开发中,应该 先有类,再有对象 类和对象的关系: 类是模板,对象是根据类这个模板创建出来的 类只有一个,而对象可以有很多个 类中定义了什么属性和方法,对象中就有什么属性和方法,不可能多,也不可能少 """ # 类的设计 """ 类名 这类事物的名字,满足大驼峰命名法(每一个单词的首字母大写,单词与单词之间没有下划线) 属性 这类事物具有什么样的特征(对象的特征描述) 方法 这类事物具有什么样的行为(对象具有的行为) """ # 定义简单的类 只包含方法 """ class 类名: def 方法1(self, 参数列表): pass def 方法2(self, 参数列表): pass 对象变量 = 类名() 类中定义方法第一个参数必须是self 在类封装的方法内部,self 就表示当前调用方法的对象自己 调用方法时,程序员不需要传递 self 参数 在方法内部 可以通过 self. 访问对象的属性 也可以通过 self. 调用其他的对象方法 """ class P1: def say(self): print('你好') a = P1() a.say() # 类的初始化 """ 当使用 类名() 创建对象时,会 自动 执行以下操作: 为对象在内存中 分配空间 —— 创建对象 为对象的属性 设置初始值 —— 初始化方法(__init__ ) """ # 通过初始化方法在类的内部设置属性 class P2: def __init__(self): self.name = '小明' def say(self): print("你好%s" % self.name) b = P2(); b.say() # 通过初始化方法传参在类的内部设置属性 class P3: def __init__(self, name): self.name = name def say(self): print("你好%s" % self.name) c = P3('小李'); c.say() # 内置方法 __del__ """ 当使用类名()创建对象时,为对象分配完空间后,自动调用 __init__ 方法 当一个 对象被从内存中销毁前,会自动调用 __del__ 方法 生命周期: 一个对象从调用类名()创建,生命周期开始 一个对象的__del__方法一旦被调用,生命周期结束 在对象的生命周期内,可以访问对象属性,或者让对象调用方法 """ class P4: def __init__(self): print('生命开始') def __del__(self): print('生命结束') d = P4() del d # 内置方法 __str__ """ 使用 print 输出 对象变量,默认情况下,会输出这个变量 引用的对象 是 由哪一个类创建的对象,以及 在内存中的地址(十六进制表示) 如果在开发中,希望使用 print 输出 对象变量时,能够打印 自定义的内容,就可以利用 __str__ 这个内置方法了 """ class P5: def __init__(self): print("生命开始") def __del__(self): print("生命结束") def __str__(self): return "我是一个类" e = P5() print(e) # 私有属性和私有方法 """ 在实际开发中,对象的某些属性或方法可能只希望在对象的内部被使用,而不希望在外部被访问到 私有属性 就是对象不希望公开的属性 私有方法 就是对象不希望公开的方法 在定义属性或方法时,在属性名或者方法名前增加两个下划线,定义的就是私有属性或方法 并没有真正意义的私有 在名称 前面加上 _类名 => _类名__名称 可以访问到类的私有属性和方法 """ class P6: def __init__(self): self.__age = 25 def __mimi(self): print('秘密') def say(self): print("年龄是" % self.__age) f = P6() # print(f.__age) # 类的外部不能调用私有属性 # f.__mimi() # 类的外部不能调用私有方法 print(f._P6__age) f._P6__mimi() # 类的继承 """ 类的单继承 子类拥有父类的所有方法和属性 class 类名(父类名): pass 子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发 子类中应该根据 职责,封装子类特有的属性和方法 继承的传递性 C类从B类继承,B类又从A类继承 那么C类就具有B类和A类的所有属性和方法 子类拥有父类以及父类的父类中封装的所有属性和方法 继承中的方法重写 当父类的方法实现不能满足子类需求时,可以对方法进行 重写(override) 重写 父类方法有两种情况: 1. 覆盖父类的方法: 如果在开发中,父类的方法实现和子类的方法实现,完全不同,就可以使用 覆盖 的方式,在子类中 重新编写 父类的方法实现 具体的实现方式,就相当于在 子类中 定义了一个 和父类同名的方法并且实现 2.对父类方法进行扩展 如果父类原本封装的方法实现是子类方法的一部分 在子类中重写父类的方法 在需要的位置使用super().父类方法 来调用父类方法的执行 代码其他的位置针对子类的需求,编写子类特有的代码实现 父类的私有属性和私有方法 子类对象 不能 在自己的方法内部,直接 访问 父类的 私有属性 或 私有方法 子类对象 可以通过 父类 的 公有方法 间接 访问到 私有属性 或 私有方法 """ class Person: def __init__(self, name): self.name = name self.__age = 25 def __mimi(self): print('这是一个秘密') def mimi(self): print('这是一个秘密') def say(self): print("你好%s" % self.name) def eating(self): print('我最爱吃') class Student(Person): def run(self): print(self.name) # print(self.__age) # 子类不能调用父类的私有属性 self.mimi() # self.__mimi() # 子类不能调用父类的私有方法 print('我跑的快') def say(self): print('我是小学生') def eating(self): super().eating() print('%s也一样爱吃' % self.name) class Stu(Student): def __str__(self): return '我爱python' aa = Student('小明') aa.say() aa.run() aa.eating() bb = Stu('张飞') bb.say() bb.eating() # 多继承 """ 类可以拥有多个父类,并且具有所有父类的属性和方法 class 子类名(父类名1, 父类名2...) pass 如果不同的父类中存在同名的方法 依据继承顺序执行 当前类、继承第一个类、第二个类... 内置属性 __mro__ 用于在多继承时判断方法、属性的调用路径 查看 方法 搜索顺序 """ class O1: def test(self): print('test...') class O2: def demo(self): print('demo...') def test(self): print('...test....') class O3(O1, O2): def say(self): print('say') class O4(O2, O1): def say(self): print('say') gg = O3() gg.test() gg.demo() gg.say() jj = O4() jj.test() # 多态 不同的子类对象 调用相同的父类方法,产生不同的执行结果 class Dog(object): def __init__(self, name): self.name = name def game(self): print("%s 蹦蹦跳跳的玩耍..." % self.name) class XiaoTianDog(Dog): def game(self): print("%s 飞到天上去玩耍..." % self.name) class Person(object): def __init__(self, name): self.name = name def game_with_dog(self, dog): print("%s 和 %s 快乐的玩耍..." % (self.name, dog.name)) # 让狗玩耍 dog.game() # 1. 创建一个狗对象 # wangcai = Dog("旺财") wangcai = XiaoTianDog("飞天旺财") # 2. 创建一个小明对象 xiaoming = Person("小明") # 3. 让小明调用和狗玩的方法 xiaoming.game_with_dog(wangcai) # 类属性和类方法 """ 封装实例的属性和方法外,类对象还可以拥有自己的属性和方法 通过类名. 的方式可以访问类的属性或者调用类的方法 类属性 就是给类对象中定义的属性 通常用来记录与这个类相关的特征 类属性不会用于记录具体对象的特征 属性的获取机制: 首先在对象内部查找对象属性、没有找到的情况下向上寻找类的属性 如果使用 对象.类属性 = 值 赋值语句,只会 给对象添加一个属性,而不会影响到 类属性的值 """ # 定义类属性 class P8: count = 0 # 类属性 def __init__(self, name): self.name = name k = P8('小呢咋') print(k.count) # 不推荐 print(P8.count) # 推荐 # 类方法和静态方法 """ 类方法 就是针对 类对象 定义的方法 在类方法内部可以直接访问类属性或者调用其他的类方法 类方法需要用 修饰器 @classmethod 来标识,告诉解释器这是一个类方法 类方法的 第一个参数 应该是 cls 可以通过cls.访问类的属性 也可以通过cls.调用其他的类方法 不是对象方法 @classmethod def 类方法名(cls): pass """ class P10: count = 0 def __init__(self, name): self.name = name def say(self): print('你好') @classmethod def test(cls): print('哈哈') @classmethod def show(cls): print(cls.count) cls.test() mn = P10 P10.show() # 静态方法 """ 静态方法 既不需要访问实例属性或者调用实例方法 也不需要访问类属性或者调用类方法 静态方法 需要用 修饰器 @staticmethod 来标识,告诉解释器这是一个静态方法 @staticmethod def 静态方法名(): pass 通过类名.调用静态方法 """ class P20: count = 0 def __init__(self, name): self.name = name @staticmethod def run(): print('快跑') P20.run() # 单例 """ 目的是让类创建的对象,在系统中只有唯一的一个实例 每一次执行类名()返回的对象,内存地址是相同的 __new__ 方法 1) 在内存中为对象分配空间 2) 返回对象的引用 Python的解释器获得对象的引用后,将引用作为第一个参数,传递给__init__ 方法 Python的解释器获得对象的引用后,将引用作为第一个参数,传递给__init__ 方法 __new__ 是一个静态方法,在调用时需要主动传递cls参数 """ # 示例 class MusicPlayer(object): def __new__(cls, *args, **kwargs): return super().__new__(cls) def __init__(self): print("初始化音乐播放对象") player = MusicPlayer() print(player) # Python 中的单例 """ 定义一个类属性,初始值是None,用于记录单例对象的引用 重写__new__ 方法 如果类属性is None,调用父类方法分配空间,并在类属性中记录结果 返回类属性中记录的对象引用 """ class MusicPlayer(object): # 定义类属性记录单例对象引用 instance = None def __new__(cls, *args, **kwargs): # 1. 判断类属性是否已经被赋值 if cls.instance is None: cls.instance = super().__new__(cls) # 2. 返回类属性的单例引用 return cls.instance # __init__ 对象初始化只被执行一次 """ 定义一个类属性 init_flag 标记是否 执行过初始化动作,初始值为 False 在 __init__ 方法中,判断 init_flag,如果为 False 就执行初始化动作 然后将 init_flag 设置为 True 这样,再次 自动 调用 __init__ 方法时,初始化动作就不会被再次执行 了 """ class MusicPlayer(object): # 记录第一个被创建对象的引用 instance = None # 记录是否执行过初始化动作 init_flag = False def __new__(cls, *args, **kwargs): # 1. 判断类属性是否是空对象 if cls.instance is None: # 2. 调用父类的方法,为第一个对象分配空间 cls.instance = super().__new__(cls) # 3. 返回类属性保存的对象引用 return cls.instance def __init__(self): if not MusicPlayer.init_flag: print("初始化音乐播放器") MusicPlayer.init_flag = True # 创建多个对象 player1 = MusicPlayer() print(player1) player2 = MusicPlayer() print(player2) # 新式类 """ object 是 Python 为所有对象提供的 基类,提供有一些内置的属性和方法 新式类:以 object 为基类的类,推荐使用 经典类:不以 object 为基类的类,不推荐使用 在 Python 3.x 中定义类时,如果没有指定父类,会 默认使用 object 作为该类的 基类 为了保证编写的代码能够同时在 Python 2.x 和 Python 3.x 运行 如果没有父类,建议统一继承自 object class 类名(object): pass """
面向对象
来源:https://www.cnblogs.com/ddf128/p/12014489.html