Python基础第七节—面向对象编程

    技术2026-08-22  14

    文章目录

    面向对象编程面向过程和面向对象区别面向过程(Precedure Oriented)思维面向对象(Object Oriented)思维 类与对象实例对象构造函数__init__()实例属性实例方法其他操作 类对象类属性类方法静态方法 __del__()方法(析构函数)和垃圾回收机制__call__()方法和可调用对象方法的特性方法没有重载方法的动态性 私有属性和私有方法(实现封装)get()和set()方法加入@property装饰器实现 面向对象三大特征封装(隐藏)继承方法的重写查看类的继承层次结构根类Objectsuper()获得父类定义 多态 其他方法的重载对象中的特殊属性对象的浅拷贝和深拷贝变量的赋值浅拷贝深拷贝 组合

    面向对象编程

    面向对象编程将数据和操作数据的方法封装在对象中,组织代码和数据的方式更加接近人的思维。Python完全支持面向对象的基本功能,如继承、多态、封装等。

    面向过程和面向对象区别

    面向过程(Precedure Oriented)思维

    面向过程更加关注的是程序的逻辑流程,是一种“执行者”思维,适合用于编写小规模的程序。首先思考“如何按步骤实现?”,并将步骤对应成方法,一步一步完成。 面向过程适合简单、不需要协作的任务。

    面向对象(Object Oriented)思维

    面向对象更加关注的是软件中对象之间的关系,是一种“设计者”思维,适合用于编写大规模程序。 面向对象可以帮助我们从宏观、整体上把握、分析整个系统,但具体到实现部分的围观操作(一个个方法),仍需要面向过程的思维。 面向对象的思考方式:遇到问题,先从问题中找“名词”,确定名词中哪些可以作为“类”,再根据问题需求确定类的属性和方法,确定类之间的关系。

    类与对象

    实例对象

    通过类,定义数据类型的属性(数据)和方法(行为)。“类将行为和状态打包在一起”。 对象是类的具体实体,一般称为“类的实例”。同一个类创建出的对象,每个对象会共享这个类的行为(类中定义的方法),但会有自己的属性值(不共享状态(数据))。 类也称为“类对象”,类的实例也称为“实例对象”。

    构造函数__init__()

    一个Python对象包含如下部分: 1.id(identity识别码) 2.type(对象类型) 3.value(对象的值) (1)属性(attribute) (2)方法(method)

    创建对象,需要定义构造函数__init__()方法,用于执行“实例对象的初始化”工作,即对象创建后, 初始化当前对象的相关属性(无返回值)。 init()要点: 1.固定名称。 2.第一个参数固定,必须为self。self即为刚创建好的实例对象。(其实名字可以任意修改,但通常写为self) 3.构造函数通常用来初始化实例对象的实例属性。如下代码即为初始化实例属性name和score:

    def __init__(self,name,score): self.name=name #self.实例属性名=初始值 self.score=score

    4.通过“类名(参数列表)”调用构造函数。调用后,将创建好的对象返回给相应变量。

    s1=Student('小红',99)

    5.init()方法:初始化创建好的对象,即:给实例属性赋值。当该类被实例化的时候就会执行该函数。 6.init()方法是可选的,如果不提供,Python 会给出默认的__init__方法。 7.new()方法:用于创建对象,但一般无需定义此方法。

    实例属性

    即为从属于实例对象的属性,也成为“实例变量”。 实例属性要点: 1.在__init__()方法中通过如下代码定义:

    self.实例属性名=初始值

    2.在本类其他实例方法中,通过如下代码访问:

    self.实例属性名

    3.创建实例对象后,通过实例对象访问:

    objt1=类名() #创建对象,调用__init__()初始化属性 objt01.实例属性名=值 #可以给已有属性赋值,也可新加属性

    例:

    class Student: def __init__(self,name,score): self.name=name self.score=score s1=Student('xiaohong',99) #通过类名()调用构造函数,在堆中参照“模具”(类对象)创建一个含有实例属性(和实例方法)的实例对象,s1为对象的引用 print(s1.name) print(s1.score) s1.age=18 #给创建好的实例对象增加属性 print(s1.age) s2=Student('xiaofang',98) print(s2.score) print(s2.age) #引用为s2的对象中并不包含age属性

    实例方法

    实例方法是从属于实例对象的方法。 定义格式:

    def 方法名(self [,形参列表]): #第一个参数必须为self,self指当前实例对象 函数体

    调用格式:

    对象.方法名([实参列表]) #不需要,也不能给self传参!

    例:

    class Student: def __init__(self,name,score): self.name=name self.score=score def say_score(self): print('{0}的分数为{1}'.format(self.name,self.score)) s1=Student('xiaohong',99) print(s1.name,s1.score) s1.say_score() #调用实例方法 Student.say_score(s1) #解释器的实际解译。调用实例方法的本质是,找到类对象内的方法(而非实例对象内的方法的引用)进行调用,以实例对象地址为实参。

    其他操作

    1.dir(object): 获得实例对象的所有属性和方法 2.object.dict: 获得实例对象的属性字典 3.isinstance(对象,类型): 判断对象是否为指定类型

    类对象

    解释器执行class语句时,就会根据类对象type,创建类对象Student。

    class Student: def __init__(self,name,score): self.name=name self.score=score def say_score(self): print('{0}的分数为{1}'.format(self.name,self.score)) print(id(s1)) print(type(s1)) #s1是实例对象,其对象类型为Student print(id(Student)) print(type(Student)) #Student类本身也是对象,其对象类型为type

    Stu=Student s2=Stu('xiaofang',99) print(s2)

    将类赋值给新变量Stu,也能实现相关调用,说明确实创建了类对象。

    类属性

    类属性是从属于类对象的属性,也称为“类变量”。 类属性可被所有实例对象共享。 类属性定义方式:

    Class 类名: 类变量名=初始值

    在类中或类外面,读写方式:

    类名.类变量名

    例:

    class Student: school='ustc' #类属性(类变量) count=0 #类属性(类变量) def __init__(self,name,score): self.name=name #实例属性 self.score=score Student.count+=1 #每调用一次__init__(),即每初始化一个实例对象,计数器就+1 def say_score(self): #实例方法 print('{0}的学校是{1}'.format(self.name,Student.school)) print('{0}的分数为{1}'.format(self.name,self.score)) s1=Student('xiaohong',99) #将Student类实例化,创建实例对象 s2=Student('xiaofang',98) s3=Student('xiaoming',97) s4=Student('xiaowang',95) s2.say_score() print('一共创建了{0}个实例对象'.format(Student.count))

    内存示意图:

    类方法

    类方法是从属于类对象的方法,需通过装饰器@classmethod定义,格式如下:

    @classmethod def 类方法名(cls [,形参列表]): 函数体

    类方法要点: 1.第一个参数必须为cls,指的是类对象本身 2.调用类方法格式:

    类名.类方法名(参数列表) #不需要也不能给cls传值

    3.类方法中访问实例属性和实例方法,会报错。类方法操作类属性,实例方法操作实例属性 4.子类继承父类方法时,传入cls是子类对象而非父类对象

    静态方法

    类中定义的与类对象无关的方法,与在模块中定义的普通函数没有区别,但需要通过类调用。 通过装饰器@staticmethod定义,格式如下:

    @staticmethod def 静态方法名([形参列表]): 函数体

    调用静态方法格式: 调用类方法格式:

    类名.静态方法名(参数列表)

    与类方法一样,静态方法中访问实例属性和实例方法,会报错。

    del()方法(析构函数)和垃圾回收机制

    del()被称为析构方法,用于实现对象被销毁时所需的操作。如:释放对象占用的资源。 要点: 1.Python有自动垃圾回收机制,当对象中引用计数为0时,由垃圾回收器自动调用__del__()方法。 2.当使用del 语句删除对象时,会调用他本身的析构函数。另外当对象在某个作用域中调用完毕,在跳出其作用域的同时析构函数也会被调用一次,清空对象内存空间。   3.del()也是可选的,如果不提供,则Python 会在后台提供默认析构函数。

    class P: def __del__(self): print('销毁对象{0}'.format(self)) p1=P() p2=P() print('p1:',p1) print('p2:',p2) del p2 print('结束')

    可见,程序结束时垃圾处理器自动调用了__del__()方法,清除了p1指向的实例对象。

    call()方法和可调用对象

    定义了__call__()方法的对象为可调用对象,可以像函数一样被调用。

    class Salary: def __call__(self,salary): print('计算工资') year_salary=salary*12 day_salary=salary//22.5 hour_salary=day_salary//8 return dict(year_salary=year_salary,month_salary=salary,day_salary=day_salary,hour_salary=hour_salary) s=Salary() print(s(50000)) #解释器实际解译的是下面一句 print(Salary.__call__(s,50000))

    方法的特性

    方法没有重载

    Python中,若在类体中定义了多个重名的方法,则只有最后一个方法有效。 建议:不要使用重名的方法。

    方法的动态性

    Python是动态语言,既可动态地为类添加新的方法,也可动态地修改类中已有的方法。 例:

    class Haha: def haha(self): print('哈哈') def hehe(s): #为Haha类动态增加hehe()方法 print('{0}说:呵呵'.format(s)) def haha2(s): #动态修改Haha类的haha()方法 print('{0}说:哈哈'.format(s)) Haha.hehe=hehe Haha.haha=haha2 h=Haha() h.hehe() h.haha()

    私有属性和私有方法(实现封装)

    Python对于类的成员没有严格的访问控制限制。关于私有属性和私有方法,有如下要点: 1.通常约定,两个下划线开头的属性为私有(private),其他为公共的(public) 2.类内部可访问私有属性(方法) 3.类外部不能直接访问私有属性(方法),但可通过**“_类名__私有属性(方法)名”**访问私有属性(方法)。

    class Employee: __location='北京' #将location设定为私有类属性 def __init__(self,name,age): self.name=name self.__age=age #将age设定为私有属性 def __work(self): #将work设定为私有方法 return '工作地点是{0},年龄是{1}'.format(self.__location,self.__age) e=Employee('xiaohong',18) print(e._Employee__age) print(e._Employee__location) print(e._Employee__work()) print(dir(e)) #获取实例对象的所有属性和方法。可见该对象中的age属性被存储为_Employee__age,work'方法被存储为_Employee__work print(e.__age) #在类外无法用访问公共属性的方式访问私有属性

    get()和set()方法

    class Employee: def __init__(self,name,salary): self.__name=name self.__salary=salary def get_salary(self): return self.__salary def set_salary(self,salary): if 1000<salary<100000: self.__salary=salary else: print('录入错误') e=Employee('xiaohong',50000) print(e.get_salary()) e.set_salary(200) e.set_salary(30000) print(e.get_salary())

    加入@property装饰器实现
    class Employee: def __init__(self,name,salary): self.__name=name self.__salary=salary @property def get_salary(self): return self.__salary @get_salary.setter def get_salary(self,salary): if 1000<salary<100000: self.__salary=salary else: print('录入错误') e=Employee('xiaohong',50000) print(e.get_salary) e.get_salary=200 e.get_salary=3000 print(e.get_salary)

    get方法和set方法及@property用法详见link

    面向对象三大特征

    封装(隐藏)

    隐藏对象的属性和实现细节,只对外提供必要的调用方法。 通过“私有属性”、“私有方法”实现封装。

    继承

    继承可以让子类拥有父类的特性,提高了代码重用性。可以在子类增加新功能,或改进已有算法。 子类可继承父类除构造方法外的所有成员。 继承的语法格式:

    class 子类类名(父类1 [,父类2,...]): #可多重继承,但多重继承会导致类的整体层次变得很复杂,不建议使用 类体

    默认父类为object类,其中定义了一些所有类都有的默认实现,如__new__() 定义子类时,必须在其构造函数中调用父类的构造函数。调用格式如下:

    父类名.__init__(self [,参数列表])

    例:

    class Person: def __init__(self,name,age): self.name=name self.__age=age #将age定义为私有属性 def say_age(self): print('年龄是{0}'.format(self.__age)) class Student(Person): #继承Person类 def __init__(self,name,age,score): Person.__init__(self,name,age) #在Student类的构造函数调用Person类的构造函数。必须显式地调用,否则解释器不会自动调用。 self.score=score stu01=Student('小芳',19,95) print(stu01.name) print(stu01._Person__age) #在类外(和子类中)调用父类的私有属性,都需要特殊方法 print(stu01.score)

    方法的重写
    class Person: def __init__(self,name,age): self.name=name self.__age=age def say_age(self): print('年龄是{0}'.format(self.__age)) class Student(Person): def __init__(self,name,age,score): Person.__init__(self,name,age) self.score=score def say_age(self): #重写say_age()方法 print('{0}的年龄是{1}'.format(self.name,self._Person__age)) #父类的私有属性可被子类继承,但在子类中需要特殊方法方可访问 stu01=Student('小芳',19,95) stu01.say_age()

    查看类的继承层次结构

    通过类的方法mro()或类的属性__mro__可输出该类的继承层次结构。 (MRO:Method Resolution Order 方法解析顺序。Python支持多继承,若子类调用的方法名字在多个父类中存在,在子类未指定父类名时,解释器将按从左至右的顺序搜索)

    根类Object

    用dir()获取object类的属性: 用dir()获取Person类的属性: 可见Person类作为Object类的子类,继承了所有属性,并另外增加了6个属性。 method是方法,但实际上也是属性,其类型为method。

    super()获得父类定义

    若在子类中想获取到父类的方法,可使用代码:

    super().方法名(参数列表)

    等同于:

    父类名.方法名(self [,参数列表])

    super()代表父类的定义,而非父类的对象。

    多态

    不同对象调用同一个方法,产生不同行为。

    class Color: def say_color(self): return '很多种颜色' class Red(Color): def say_color(self): return '红色' class Blue(Color): def say_color(self): return '蓝色' class Green: def say_color(self): return '绿色' def color(c): if isinstance(c,Color): print(c.say_color()) else: print('不知道') color(Green()) color(Blue()) color(Red()) color(Color())

    其他

    方法的重载
    class Person: def __init__(self,name): self.name=name def __add__(self,other): return '{0}+{1}'.format(self.name,other.name) def __mul__(self,other): return self.name*len(other.name) p1=Person('小红') p2=Person('小芳') print(p1+p2) print(p1.__add__(p2)) print(p1*p2) print(p1.__mul__(p2))

    对象中的特殊属性
    print(p1.__dict__) #对象的属性字典 print(p1.__class__) #对象所属的类 print(Student.__bases__) #类的基类元组(多继承情况下) print(Student.__base__) #类的基类 print(Student.__mro__) #类的继承层次结构 print(Color.__subclasses__()) #子类列表

    对象的浅拷贝和深拷贝
    变量的赋值

    只是形成两个变量,实际指向的是同一个对象。

    浅拷贝

    Python中的拷贝一般都是浅拷贝。 只拷贝对象,不拷贝对象包含的子对象。因此,源对象和拷贝的对象会引用同样的子对象。

    深拷贝

    递归拷贝对象中包含的子对象。因此,源对象和拷贝对象引用的子对象不同。 例:

    import copy class iPhone: def __init__(self,screen,cpu): self.screen=screen self.cpu=cpu class Screen: def show(self): print('screen:',self) class Cpu: def calculate(self): print('cpu:',self) ip1=iPhone(Screen(),Cpu()) ip2=ip1 ip3=copy.copy(ip1) ip4=copy.deepcopy(ip1) print(ip1,ip1.screen,ip1.cpu) print(ip2,ip2.screen,ip2.cpu) #ip2指向的对象及其包含的子对象都与ip1一致 print(ip3,ip3.screen,ip3.cpu) #ip3指向的对象与ip1不一致,但包含的子对象一致 print(ip4,ip4.screen,ip4.cpu) #ip4指向的对象与ip1不一致,包含的子对象也不一致

    组合

    除继承外,也可通过组合实现代码复用。 例1:

    class iPhone: def __init__(self,screen,cpu): self.screen=screen self.cpu=cpu class Screen: def show(self): print('screen:',self) class Cpu: def calculate(self): print('cpu:',self) ip1=iPhone(Screen(),Cpu()) ip1.screen.show() ip1.cpu.calculate()

    例2:

    class A: def say(self): print('hahaha') class B: def __init__(self,a): self.a=a B(A()).a.say()

    Processed: 0.013, SQL: 9