Python----Python高级(面向对象:封装、继承、多态,方法,属性,拷贝,组合,单例)

一、封装

隐藏对象的属性和实现细节,只对外提供必要的方法。相当于将"细节封装起来",只对外暴露"相关调用方法"。
Python追求简洁的语法,没有严格的语法级别的"访问控制符",更多的是依靠程序员自觉实现。

python 复制代码
class BankAccount:  
    def __init__(self, balance=0):  
        self.__balance = balance  # 使用双下划线使属性私有  
    
    def deposit(self, amount):  
        if amount > 0:  
            self.__balance += amount  
            
    def withdraw(self, amount):  
        if 0 < amount <= self.__balance:  
            self.__balance -= amount  
        else:  
            print("余额不足或无效的取款金额")  
    
    def get_balance(self):  
        return self.__balance  

account = BankAccount(100)  
account.deposit(50)  
print(account.get_balance())  # 输出: 150  
account.withdraw(200)          # 输出: 余额不足或无效的取款金额

二、继承

2.1继承

继承可以让子类具有父类的特性,提高了代码的重用性。

从设计上是一种增量进化,原有父类设计不变的情况下,可以增加新的功能,或者改进已有的算法。
继承是面向对象编程的三大特征之一。继承让我们更加容易实现类的扩展。实现代码的重用。

如果一个新类继承自一个设计好的类,就直接具备了已有类的特征,就大大降低了工作难度。已有的类,我们称为"父类或者基类",新的类,我们称为"子类或者派生类"。

2.1.1、语法格式

Python支持多重继承,一个子类可以继承多个父类

class 子类类名(父类1[,父类2,...]):

类体
如果在类定义中没有指定父类,则默认父类是object类。也就是说,object是所有类的父类,里面定义了一些所有类共有的默认实现,比如:new()
子类不重写 init,实例化子类时,会自动调用父类定义的 init

子类重写了__init__ 时,实例化子类,就不会调用父类已经定义的 init

如果重写了__init__ 时,要使用父类的构造方法,可以使用 super 关键字,也可以使用如下格式调用:

python 复制代码
class Person:
  def __init__(self,name,age):
    print("Person的构造方法")
    self.name = name
    self.age = age

  def say_age(self):
    print(f"{self.name}的年龄是:{self.age}")


class Student(Person):

  def __init__(self,name,age,score):
    # 子类并不会自动调用父类的__init__(),我们必须显式的调用它。
    # Person.__init__(self, name, age)
    # super(Student,self).__init__(name,age)

    print("Student的构造方法")
    self.name = name
    self.age = age
    self.score = score


s1 = Student("张三",15,85)
s1.say_age()#张三的年龄是:15
print(dir(s1))
#['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'say_age', 'score']

2.1.2、类成员的继承和重写

  1. 成员继承:子类继承了父类除构造方法之外的所有成员。

    ⚠️(私有属性、私有方法也被继承)

  2. 方法重写:子类可以重新定义父类中的方法,这样就会覆盖父类的方法,也称为"重写"

python 复制代码
class Person:
  def __init__(self,name,age):
    self.name = name
    self.age = age

  def say_age(self):
    print(self.name,"的年龄是:",self.age)

  def say_name(self):
    print("我是",self.name)


class Student(Person):

  def __init__(self,name,age,score):
    self.name = name
    self.age = age
    self.score = score

  def say_score(self):
    print(self.name,"的分数是:",self.score)

  def say_name(self):   #重写父类的方法
    print("报告老师,我是",self.name)

s1 = Student("张三",51,88)
s1.say_score()#张三 的分数是: 88
s1.say_name()#报告老师,我是 张三
s1.say_age()#张三 的年龄是: 51

查看类的继承层次结构

python 复制代码
class A:
    pass
class B(A):
    pass
class C(B):
    pass

print(C.mro())
# [<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]

object类是所有类的父类,因此所有的类都有object类的属性和方法。

2.1.3、dir()查看对象属性

python 复制代码
class Person:
  def __init__(self,name,age):
    self.name = name
    self.age = age

  def say_age(self):
    print(self.name,"的年龄是:",self.age)

obj = object()
print(dir(obj))
#['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

s2 = Person("张三",18)
print(dir(s2))
#['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'say_age']

2.1.4、重写__str__()方法

object有一个__str__()方法,用于返回一个对于"对象的描述"。

内置函数str(对象),调用的就是__str__()

str()经常用于print()方法,帮助我们查看对象的信息。str()可以重写

python 复制代码
class Person:
  def __init__(self,name,age):
    self.name = name
    self.__age = age

  def __str__(self):
    '''将对象转化成一个字符串,一般用于print方法'''
    print("重写__str__方法")
    return "名字是:{0},年龄是{1}".format(self.name,self.__age)

p = Person("张三",18)
print(p)#名字是:张三,年龄是18
s = str(p)#重写__str__方法

2.1.5、多重继承

Python支持多重继承,一个子类可以有多个"直接父类"。这样,就具备了"多个父类"的特点。但是由于,这样会被"类的整体层次"搞的异常复杂,尽量避免使用。

python 复制代码
class A:
  def aa(self):
    print("aa")

class B:
  def bb(self):
    print("bb")

class C(B,A):
  def cc(self):
    print("cc")

c = C()
c.cc()#cc
c.bb()#bb
c.aa()#aa

2.1.6、MRO方法解析顺序

Python支持多继承,如果父类中有相同名字的方法,在子类没有指定父类名时,解释器将"从左向右"按顺序搜索。
MRO(Method Resolution Order):方法解析顺序。 我们可以通过mro()方法获得"类的层次结构",方法解析顺序也是按照这个"类的层次结构"寻找的。

python 复制代码
class A:
  def aa(self):
    print("aa")

  def say(self):
    print("say AAA!")

class B:
  def bb(self):
    print("bb")

  def say(self):
    print("say BBB!")
class C(B,A):
  def cc(self):
    print("cc")

c = C()
print(C.mro())#[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
c.say()#say BBB!

2.1.7、super()获得父类定义

在子类中,如果想要获得父类的方法时,我们可以通过super()来做。

super()代表父类的定义,不是父类对象。

调用父类的构造方法:

super(子类名称,self).init(参数列表)

python 复制代码
class A:
  def __init__(self):
    print("A的构造方法")

  def say(self):
    print("A: ",self)
    print("say AAA")

class B(A):
  def __init__(self):
    super().__init__() #调用父类的构造方法
    print("B的构造方法")
  def say(self):
    #A.say(self)   调用父类的say方法
    super().say()  #通过super()调用父类的方法
    print("say BBB")

b = B()
b.say()

2.2、讲故事继承

1.在很久以前,有一位技艺精湛的蛋糕师,他可以通过自己的手艺制作出味道鲜美的蛋糕

python 复制代码
class Master(object):
    def __init__(self):
        self.cake="古法蛋糕配方"
    def make_cake(self):
        print(f"根据{self.cake}制作一份蛋糕")
    def hobby(self):
        print(f"他的爱好是饮酒")

2.随着时间的流逝,蛋糕师的逐渐衰老,但是他希望在他剩余的岁月里可以找到一个学徒,可以继承他的手艺

python 复制代码
class Student(Master):
    pass
s=Student()
s.make_cake()#根据古法蛋糕配方制作一份蛋糕

3.随着时间的流逝,蛋糕店生意只剩一般,学徒发现另一半人更加喜欢新式蛋糕,后来他为了学会这一制作方法,于是他就去了专属的蛋糕学校去学习这一种新的蛋糕

python 复制代码
class School(object):
    def __init__(self):
        self.cake="新式蛋糕配方"
    def make_cake(self):
        print(f"根据{self.cake}制作一份蛋糕")
  1. 学成之后,学徒现在会两种蛋糕制作
python 复制代码
class Student(Master,School):
    def make_old_cake(self):
        Master.__init__(self)
        print(f"根据{self.cake}制作一份蛋糕")
    def make_new_cake(self):
        School.__init__(self)
        print(f"根据{self.cake}制作一份蛋糕")

s=Student()
s.make_old_cake()#根据古法蛋糕配方制作一份蛋糕
s.make_new_cake()#根据新式蛋糕配方制作一份蛋糕

5.后来他根据自己师傅的古法蛋糕和新型蛋糕创造出来了属于自己的手艺--小鱼蛋糕

python 复制代码
class Student(Master,School):
    def __init__(self):
        self.cake="小鱼蛋糕配方"
    def make_fish_cake(self):
        print(f"根据{self.cake}制作一份蛋糕") 

6.随着小鱼蛋糕店越来越火,有人的喜欢小鱼蛋糕 有一部分人喜欢古法蛋糕, 有一部分人喜欢 新式蛋糕。

python 复制代码
class Master(object):  
    def __init__(self):  
        self.old_cake_recipe = "古法蛋糕配方"  

    def make_old_cake(self):  
        print(f"根据{self.old_cake_recipe}制作一份蛋糕")  

    def hobby(self):  
        print("他的爱好是饮酒")  


class School(object):  
    def __init__(self):  
        self.new_cake_recipe = "新式蛋糕配方"  

    def make_new_cake(self):  
        print(f"根据{self.new_cake_recipe}制作一份蛋糕")  


class Student(Master, School):  
    def __init__(self):  
        Master.__init__(self)
        School.__init__(self)
        self.fish_cake_recipe = "小鱼蛋糕配方"

    def make_old_cake(self):  
        print(f"根据{self.old_cake_recipe}制作一份蛋糕")  

    def make_new_cake(self):  
        print(f"根据{self.new_cake_recipe}制作一份蛋糕")  

    def make_fish_cake(self):  
        print(f"根据{self.fish_cake_recipe}制作一份蛋糕")  


s = Student()  
s.make_old_cake()  # 根据古法蛋糕配方制作一份蛋糕  
s.make_new_cake()  # 根据新式蛋糕配方制作一份蛋糕  
s.make_fish_cake()  # 根据小鱼蛋糕配方制作一份蛋糕

三、多态

多态是指同一个方法调用由于对象不同会产生不同的行为。生活中这样的例子比比皆是:同样是休息方法,人不同休息方法不同。张三休息是睡觉,李四休息是玩游戏,程序员休息是"敲几行代码"。
注意事项:

  1. 多态是方法的多态,属性没有多态。

  2. 多态的存在有2个必要条件:继承、方法重写

python 复制代码
class Animal:
  def shout(self):
    print("动物叫了一声")

class Dog(Animal):
  def shout(self):
    print("小狗,汪汪汪")

class Cat(Animal):

  def shout(self):
    print("小猫,喵喵喵")

def animal_shout(a):
  a.shout()  #传入的对象不同,shout方法对应的实际行为也不同。

animal_shout(Dog())#小狗,汪汪汪
animal_shout(Cat())#小猫,喵喵喵

四、特殊方法和运算符重载

方法 说明 例子
__init__ 构造方法 对象创建和初始化:p = Person()
__del__ 析构方法 对象回收
__repr__,__str__ 打印,转换 print(a)
__call__ 函数调用 a()
__getattr__ 点号运算 a.xxx
__setattr__ 属性赋值 a.xxx = value
__getitem__ 索引运算 a[key]
__setitem__ 索引赋值 a[key]=value
__len__ 长度 len(a)
运算符 特殊方法 说明
+ __add__ 加法
- __sub__ 减法
< <= == __lt__ __le__ __eq__ 比较运算符
> >= != __gt__ __ge__ __ne__ 比较运算符
` ^ &` __or__ __xor__ __and__
<< >> __lshift__ __rshift__ 左移、右移
* / % // __mul__ __truediv__ __mod__ __floordiv__ 乘、浮点除、模运算(取余)、整数除
** __pow__ 指数运算
python 复制代码
#测试运算符的重载

class Person:
  def __init__(self,name):
    self.name = name

  def __add__(self, other):
    if isinstance(other,Person):
      return "{0}--{1}".format(self.name,other.name)
    else:
      return "不是同类对象,不能相加"

  def __mul__(self, other):
    if isinstance(other,int):
      return self.name*other
    else:
      return "不是同类对象,不能相乘"

p1 = Person("张三")
p2 = Person("李四")

x = p1 + p2
print(x)#张三--李四
print(p2*3)#李四李四李四

五、特殊属性

Python对象中包含了很多双下划线开始和结束的属性,这些是特殊属性,有特殊用法。

特殊属性 含义
obj.__dict__ 对象的属性字典
obj.__class__ 对象所属的类
class.__bases__ 表示类的父类(多继承时,多个父类放到一个元组中)
class.__base__ 类的父类
class.__mro__ 类层次结构
class.__subclasses__() 子类列表
python 复制代码
#测试特殊属性
class A:
  pass

class B:
  pass

class C(B,A):

  def __init__(self,nn):
    self.nn = nn

  def cc(self):
    print("cc")

c = C(3)

print(c.__dict__)#{'nn': 3}
print(c.__class__)#<class '__main__.C'>
print(C.__bases__)#(<class '__main__.B'>, <class '__main__.A'>)
print(C.mro())#[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
print(A.__subclasses__())#[<class '__main__.C'>]

六、对象的浅拷贝和深拷贝

浅拷贝

Python拷贝一般都是浅拷贝。

浅拷贝:拷贝时,拷贝源对象,但对象包含的子对象内容不拷贝。

深拷贝

使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象。

深拷贝:拷贝时,拷贝源对象,也递归拷贝对象中包含的子对象

python 复制代码
#测试对象的引用赋值、浅拷贝、深拷贝
import copy

class MobilePhone:
  def __init__(self,cpu):
    self.cpu = cpu

class CPU:
  pass

c = CPU()
m = MobilePhone(c)

print("----浅拷贝-------")
m2 = copy.copy(m)  #m2是新拷贝的另一个手机对象
print("m:",id(m))
print("m2:",id(m2))
print("m的cpu:",id(m.cpu))
print("m2的cpu:",id(m2.cpu))  #m2和m拥有了一样的cpu对象
'''
m: 2705913095008
m2: 2705913088912
m的cpu: 2705910961056
m2的cpu: 2705910961056
'''
print("----深拷贝--------")
m3 = copy.deepcopy(m)
print("m:",id(m))
print("m3:",id(m3))
print("m的cpu:",id(m.cpu))
print("m3的cpu:",id(m3.cpu))  #m3和m拥有不一样的cpu对象
'''
m: 2705913095008
m3: 2705913102256
m的cpu: 2705910961056
m3的cpu: 2705913100192
'''

七、组合

除了继承,"组合"也能实现代码的复用!"组合"核心是"将父类对象作为子类的属性"。

python 复制代码
class MobilePhone:
  def __init__(self,cpu,screen):
    self.cpu = cpu
    self.screen = screen


class CPU:

  def calculate(self):
    print("计算,算个12345")


class Screen:
  def show(self):
    print("显示一个好看的画面,亮瞎你的钛合金大眼")


c = CPU()
s = Screen()
m = MobilePhone(c,s)
m.cpu.calculate()    #通过组合,我们也能调用cpu对象的方法。相当于手机对象间接拥有了"cpu的方法"
m.screen.show()

八、设计模式

设计模式是面向对象语言特有的内容,是我们在面临某一类问题时候固定的做法,设计模式有很多种,比较流行的是:GOF(Goup Of Four)23种设计模式。

8.1、工厂模式

工厂模式实现了创建者和调用者的分离,使用专门的工厂类将选择实现类、创建对象进行统一的管理和控制。

python 复制代码
class CarFactory:
  def createCar(self,brand):
    if brand == "奔驰":
      return Ben()
    elif brand == "宝马":
      return BM()
    elif brand == '比亚迪':
      return BYD()
    else:
      return "未知品牌,无法创建"


class Ben:
    pass
    # print('Ben')

class BM:
    pass
    # print('BM')


class BYD:
    pass
    # print('BYD')

c= CarFactory()
c1 = c.createCar("奔驰")
c2 = c.createCar("宝马")
print(c1)#<__main__.Ben object at 0x0000027604FD01A0>
print(c2)#<__main__.BM object at 0x0000027604F58CE0>

8.2、单例模式

单例模式(Singleton Pattern)的核心作用是确保一个类只有一个实例,并且提供一个访问该实例的全局访问点。

单例模式只生成一个实例对象,减少了对系统资源的开销。当一个对象的产生需要比较多的资源,如读取配置文件、产生其他依赖对象时,可以产生一个"单例对象",然后永久驻留内存中,从而极大的降低开销。

python 复制代码
class Single(object):
    # 是一个单例模式

    # 定义一个类属性用于记录是否创建过对象
    __instance = None

    # 重写__new__这个方法
    def __new__(cls):

        if cls.__instance is None:
            # Single类没有创建过对象。
            cls.__instance = super().__new__(cls)

        return cls.__instance

# 通过Single类创建对象
s1 = Single()
s2 = Single()

print(f"id(s1):{id(s1)}\nid(s2):{id(s2)}")
# id(s1):2705913093136
# id(s2):2705913093136

8.3、工厂和单例模式结合

python 复制代码
class CarFactory:
  __obj = None      #类属性
  __init_flag = True


  def create_car(self,brand):
    if brand == "奔驰":
      return Ben()
    elif brand == "宝马":
      return BM()
    elif brand == '比亚迪':
      return BYD()
    else:
      return "未知品牌,无法创建"


  def __new__(cls, *args, **kwargs):
    if cls.__obj ==None:
      cls.__obj = object.__new__(cls)

    return cls.__obj

  def __init__(self):
    if CarFactory.__init_flag:
      print("init CarFactory....")
      CarFactory.__init_flag = False

class Ben:
    pass
    # print('Ben')

class BM:
    pass
    # print('BM')


class BYD:
    pass
    # print('BYD')

factory = CarFactory()
c1 = factory.create_car("奔驰")
c2 = factory.create_car("比亚迪")
print(id(c1))#2705912600272
print(id(c2))#2705912609632

factory2 = CarFactory()
print(id(factory))#2705912785776
print(id(factory2))#2705912785776

九、思维导图

相关推荐
珹洺30 分钟前
踏上 C++ 编程之旅:开篇之作
开发语言·c++
Yeats_Liao37 分钟前
Java List过滤 Stream API filter() 应用
java·开发语言·list
周杰伦_Jay1 小时前
Ubuntu20.4和docker终端指令、安装Go环境、安装搜狗输入法、安装WPS2019:保姆级图文详解
linux·python·ubuntu·docker·centos
qingy_20461 小时前
【算法】图解二叉树的前中后序遍历
java·开发语言·算法
从零开始学习人工智能2 小时前
安装指南:LLaMA Factory、AutoGPTQ 和 vllm
人工智能·python·深度学习·算法
是小白_鸭2 小时前
(RAG系列)FastGPT批量添加索引
python·ai·语言模型
蒙娜丽宁2 小时前
【人工智能】Python中的自动化机器学习(AutoML):如何使用TPOT优化模型选择
人工智能·python·自动化
测试19982 小时前
接口测试之postman的使用
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·postman
jerry2011082 小时前
python之二维几何学习笔记
开发语言·python·算法
云端 架构师2 小时前
PL/SQL语言的文件操作
开发语言·后端·golang