Python学习笔记-面向对象

Python面向对象概述

类和对象是面向对象程序设计的两个重要概念。
类和对象的关系即数据类型与变量的关系,根据一个类可以创建多个对象,而每个对象只能是某一个类的对象。
类规定了可以用于存储什么数据,而对象用于实际存储数据,每个对象可存储不同的数据。

类的定义和创建实例

可以直接创建新的类,也可以基于一个或多个已有的类创建新的类;
们既可以创建一个空的类,然后再动态添加属性和方法,也可以在创建类的同时设置属性和方法。
类中的属性对应前面所学习的变量(实例),而类中的方法对应前面所学习的函数。
通过类,可以把数据和操作封装在一起,从而使得程序结构更加清晰,这也就是所谓的类的封装性。

class  类名:
	语句1
	语句2
	...
	...
	语句N

例:定义一个空类。
class Student: # 定义一个名字为Student的类
	pass  # 一个空语句,起到占位作用,表示Student类中没有任何属性和方法。

例:创建Student类对象。
Class Student:
	pass
	
if __name__=='__main__': 
	stu=Student()  # 创建Student类的对象,并将创建的对象赋给变量stu
	print(stu)  # 输出stu:<__main__.Student object at 0x000001523015BAC0>

注意:每次创建对象时,系统都会在内存中选择一块区域分配给对象,每次选择的内存通常时不一样的。因此,实际运行时会看到一个不同的stu对象地址。

类属性定义及其访问

定义类时指定类属性

class Student: # 定义Student类
	name='Unknown'  # 定义Student类中有一个name属性

对类属性的访问

既可以通过类名访问,也可以通过该类的对象访问。
类名.属性名 
对象名.属性名

例:类属性的访问示例。

class Student: # 定义Student类
	name='Unknown'  # 定义Student类中有一个name属性
if __name__=='__main__':
	stu1=Student() # 创建Studentl类对象stu1
	stu2=Student() # 创建Studentl类对象stu2
	print('第7行输出:stu1 %s,stu2 %s'%(stu1.name,stu2.name))
	Student.name='未知' # 将Student的类数下name赋值为未知'
	print('第9行输出:',Student.name)
	print('第10行输出:stu1%s,stu2%s'%(stu1.name,stu2.name))

stu1.name='李晓明'  # 将stu1的name属性赋值为'李晓明'
stu2.name='马红'   # 将stu2的name属性赋值为'马红'
print('第13行输出:',Student.name)
print('第14行输出:stu1%s,stu2%s'%(stu1.name,stu2.name))7行输出:stu1 Unknown,stu2 Unknown
第8行输出: 未知
第10行输出:stu1未知,stu2未知
第13行输出: 未知
第14行输出:stu1李晓明,stu2马红

为对象动态绑定新属性

Python作为一种动态语言,除了可以在定义类时指定类属性外,还可以动态地为已创建的对象绑定新的属性。
例:为对象绑定新属示例。
class Student: # 定义Student类
	name='Unknown'  # 定义Student类中有一个name属性
if __name__=='__main__':
	stu1=Student()
	stu2=Student()
stu1.age=19 # 为对象stu1动态绑定新的属性age。
print('stu1姓名:%s,年龄:%d'%(stu1.name,stu1.age)) #输出姓名和年龄

stu1姓名:Unknown,年龄:19

类中普通方法定义及调用

与普通函数定义一样,类中的方法在定义时也需要时使用def关键字(也可以有默认参数值)。
类中的方法分为两种,普通方法和内置方法。
	普通方法:需要通过类的实例对象根据方法名调用;
		实例对象名.方法名(实参列表)
	内置方法:是在特定情况下由系统自动执行

注意:类的普通方法必须通过实例对象调用,而不能通过类名直接调用。这是因为通过实例对象调用时会自动将该实例对象传给self,而通过类调用时则不会有这个隐含的参数传递。

普通方法定义和调用

第一个参数需要对应调用方法时所使用的实例对象(一般为self,但也可以改为其他名字)
class Student:
    name='Unknown'

    def SetName(self,newname,newid='Unknown'):  # 定义类的普通方法Setname且有一个默认参数newid
        self.name=newname # 将self对应实例对象中的name属性值赋为newname

    def PrintName(self):  # 定义类的普通方法Printname
        print('姓名:%s'%self.name)

if __name__=='__main__':
    stu1=Student()
    stu2=Student()
    stu1.SetName('李晓明')  # 实例对象名.方法名(实参列表),self就是实例对象stu1,而newname='李晓明'
    stu2.SetName('马红')

    stu1.PrintName()  # self=stu1
    stu2.PrintName()

私有属性

在定义类时,如果一个类属性名是以__(两个下划线)开头,则该类属性为私有属性。
在类内可以直接访问,而在类外无法直接访问的属性。那如果需要在类外访问私有属性怎么办?私有属性名前面加上"_类名"(stu._Student__id)。
class Student:
    name='未知' # 定义Student类中有一个name属性
    __id='未知' # 定义Student类中有一个__id私有属性
    def SetInfo(self,newname,newid):  #定义SetInfo方法
        self.name=newname
        self.__id=newid  # 将self对应实例对象的__id属性赋为newiid
    def PrintInfo(self):
        print('姓名:%s,身份证号:%s'%(self.name,self.__id) ) # 类内访问私有属性__id

if __name__=='__main__':
    stu=Student() # 定义Student类对象stu
    stu.SetInfo('李晓明','120XXXXXXXXXXXXXX') # 通过实例对象stu调用SetInfo方法
    stu.PrintInfo()
    
print('身份证号 :%s'%stu._Student__id) # 类外访问私有属性,需要在私有属性__id前面加上类名"_Student"

姓名:李晓明,身份证号:120XXXXXXXXXXXXXX
身份证号 :120XXXXXXXXXXXXXX

构造方法

__init__在创建一个类对象时会自动执行,负责完成新创建对象的初始化工作。
例:只有一个参数的构造方法示例。
class Student:

    def __init__(self): # 定义构造方法
        print('构造方法被调用!')
        self.name='未知' # 将self对应的name属性赋为形参name的值
        
    def PrintInfo(self): # 定义一个普通方法
        print('姓名:%s'%self.name)
        
if __name__ == '__main__':
    stu1=Student() # 创建Student类对象stu1,自动执行构造方法。
    stu1.PrintInfo() # 通过stu1对象调用PrintInfo方法。
    
构造方法被调用!
姓名:未知
例:带默认参数的构造方法示例。
class Student:
    def __init__(self,name='未知'): # 定义带默认参数的构造方法
        print('构造方法被调用!')
        self.name=name
    def PrintInfo(self):
        print('姓名:%s'%self.name)
if __name__ == '__main__':
    stu1=Student()
    stu2=Student('李晓明')
    stu1.PrintInfo()
    stu2.PrintInfo()
    
构造方法被调用!
构造方法被调用!
姓名:未知
姓名:李晓明

析构方法

__del__:在销毁一个类对象时会自动执行,负责完成待销毁对象的资源清理工作,如关闭文件等。
注:类对象销毁有如下三种情况:
(1)局部变量的作用域结束。
(2)使用del删除对象。
(3)程序结束时,程序中的所有对象都将被销毁。
注意:如果多个变量对应同一片内存空间,则只有这些变量都删除后才会销毁这片内存空间中所保存的对象,也才会自动执行析构方法。
class Student:
    def __init__(self, name):  # 定义构造方法
        self.name = name
        print('姓名为%s的对象被创建!'%self.name)
    def __del__(self):  # 定义析构方法
        print('姓名为%s的对象被销毁!'%self.name)
def func(name): 
    stu=Student(name)
if __name__=='__main__':
    stu1=Student('李晓明')
    stu2 = Student('马红')
    stu3=stu2
    del stu2 # 使用del删除stu2对象,但还有一个stu3所对应的相同内存空间。 
    func('张刚') # 调用func函数
    del stu3 # 使用del删除stu3函数
    stu4=Student('刘建')
    
姓名为李晓明的对象被创建!
姓名为马红的对象被创建!
姓名为张刚的对象被创建!
姓名为张刚的对象被销毁!
姓名为马红的对象被销毁!
姓名为刘建的对象被创建!	# 在thonny环境中,输出到此结束。
姓名为李晓明的对象被销毁! # 程序结束所有对象都将被销毁
姓名为刘建的对象被销毁!	# 程序结束所有对象都将被销毁

常用内置方法

__str__方法:返回值必须是字符串。对类对象进行处理时或者调用Python内置函数format()和print()时自动执行。

class Complex: # 定义复数类Complex
    def __init__(self, real,image):
        self.real=real
        self.image=image

    def __str__(self): # 定义内置方法__str__
        return str(self.real)+ '+' +str(self.image) + 'i'
if __name__ == '__main__':
    c=Complex(3.2,5.3)  定义Complex类对象c
    print(c)
    
3.2+5.3i

比较运算的内置方法

###用于比较对象大小的内置方法
gt(self,other) lt(self,other) ge(self,other) le(self,other) eq(self,other) ne(self,other)

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age=age

    def __le__(self, other):  # 定义内置方法__le__
        return self.age <= other.age
if __name__ == '__main__':
    stu1=Student('李晓明', 19)
    stu2=Student('马红',20)
    print('马红的年龄小于等于李晓明的年龄:',stu2<=stu1)
    
马红的年龄小于等于李晓明的年龄: False

继承的概念

如果一个类C1通过继承已有类C而创建,则将C1称作子类(sub class),将C称作基类、父类或超类(base class、super class)。

子类会继承父类中定义的所有属性和方法,另外也能在子类中增加新的属性和方法。

单继承和多继承

如果一个子类只有一个父类,则将这种继承关系称为单继承;如果一个子类有两个或更多的父类,则将这种继承关系称为多重继承。

注:一个类可能在一种继承关系中是子类,而在另一种继承关系中是父类。

子类的定义

class 子类名(父类名1,父类名2,...,父类名M)
	语句1
	语句2
	...
	语句N
class Person:
    def SetName(self, name):
        self.name = name

class Student(Person):  # 以Person类作为父类定义子类Student
    def SetSno(self,sno):
        self.sno = sno
        
class Teacher(Person):
    def SetTno(self,tno):
        self.tno = tno

class TA(Student,Teacher):
    def SetTeach(self,teacher):
        self.teacher = teacher

if __name__ == '__main__':
    stu=Student()  # 定义Student类对象stu
    stu.SetSno('1810100')  # 调用Student类中定义的SetSno方法
    stu.SetName('李晓明')  # 调用Student类:从父类Person继承过来的SetName方法
    print('学号:%s,姓名:%s'%(stu.sno,stu.name))
    
    t=Teacher() # 定义Teacher类对象t
    t.SetTno('998012') # 调用Teacher类中定义的SetTno方法
    t.SetName('马红')  # 调用Teacher类:从父类Person继承过来的SetName方法
    print('教工号:%s,姓名:%s'%(t.tno,t.name))
 
学号:1810100,姓名:李晓明
教工号:998012,姓名:马红 

方法重写和鸭子类型

方法重写:是指子类可以对从父类中继承过来的方法进行重新定义,从而使得子类对象可以表现出与父类对象不同的行为。

例:方法重写示例。
class Person:
    def __init__(self, name):
        self.name = name
    def PrintInfo(self):  # 定义基类中的PrintInfo方法
        print('姓名:%s'%self.name)
        
class Student(Person):   #定义一个子类(单继承)
    def __init__(self,sno,name):
        self.sno = sno
        self.name = name
    def PrintInfo(self): # 和父类Person中同名的方法
        print('学号:%s,姓名:%s'%(self.sno,self.name))
        
def PrintPersonInfo(person):
    print('PrintPersonInfo函数中输出的结果',end='#')
    person.PrintInfo() # 通过person调用PrintInfo方法

if __name__ == '__main__':
    p=Person('李晓明')  # 创建Person对象类p
    stu=Student('18100100','李晓明')  #创建Student类对象stu
    p.PrintInfo()   # 调用Person类中的PrintInfo方法
    stu.PrintInfo()   # 调用Student类中的PrintInfo方法
    PrintPersonInfo(p)  # p对象所属Person类中的PrintInfo方法
    PrintPersonInfo(stu) # stu对象所属Student类中的PrintInfo方法
    
姓名:李晓明
学号:18100100,姓名:李晓明
PrintPersonInfo函数中输出的结果#姓名:李晓明
PrintPersonInfo函数中输出的结果#学号:18100100,姓名:李晓明
多态

指在执行同样代码的情况下,系统会根据对象实际所属的类去调用相应类中的方法。

鸭子类型

关注的不是对象所属的类,而是一个对象能够如何使用。
在Python中编写一个函数,传递实参前其参数的类型并不确定,在函数中使用形参进行操作时只需要传入的对象能够支持该操作程序就能正常执行。

class Person:
    def CaptureImage(self):
        print('Person类中的CaptureImage方法被调用!')

class Camera:
    def CaptureImage(self):
        print('Camera中的CaptureImage方法被调用!')

def CaptureImagetest(arg):
    arg.CaptureImage()  # 通过arg调用CaptureImage方法

if __name__ == '__main__':
    p=Person() # 定义Person类对象p
    c=Camera() # 定义Camera类对象c
    CaptureImagetest(p)  # arg=Person 实际执行的是Person类中的CaptureImage
    CaptureImagetest(c)  # arg=Camera 实际执行的是Camera类中的CaptureImage

super方法

用于获取父类的代理对象,以执行已在子类中被重写的父类方法,其语法格式为:

super([类名[,对象名或类名]])
例:super(Postgraduate,self).__init__(sno,name)

第一个参数是要获取父类代理对象的类名。
第二个参数如果传入对象名,则该对象所属的类必须是第一个参数指定的类或该类的子类,找到父类对象的self会绑定到这个对象上;如果传入类名,则该类型必须是第一个参数指定的类的子类。

在一个类A的定义中调用super方法时,两个参数都可以省略。此时,super()等价于super(A,self),即获取A的父类代理对象,且获取到的父类代理对象中的self绑定到当前A类对象的self上。

class Person:
    def __init__(self, name):
        print('Person类构造方法被调用!')
        self.name = name

class Student(Person):
    def __init__(self,sno,name):
        print('Student类构造方法被调用!')
        super().__init__(name)  #调用父类的构造方法
        self.sno = sno

class Postgraduate(Student):
    def __init__(self,sno,name,tutor):
        print('Postgraduate类构造方法被调用!')
        super().__init__(sno,name)  #调用父类的构造方法
        #上面语句等同于:
        #super(Postgraduate,self).__init__(sno,name)
        self.tutor = tutor

if __name__=='__main__':
    pg=Postgraduate('1810100','李晓明','马红')  # 创建Postgraduate类对象pg
    print('学号:%s,姓名:%s,导师:%s'%(pg.sno,pg.name,pg.tutor))
    
Postgraduate类构造方法被调用!
Student类构造方法被调用!
Person类构造方法被调用!
学号:1810100,姓名:李晓明,导师:马红

内置函数

isinstance:

用于判断一个对象所属的类是否是指定类或指定类的子类;

issubclass

用于判断一个类是否是另一个类的子类;

type

用于获取一个对象所属的类。

class Person:
    pass

class Student(Person):
    pass
    
class Flower:
    pass
    
if __name==('__main__'):
    stu=Student()
    f=Flower()
    print('stu是Person类或其子类对象:',isinstance(stu,Person))
    print('stu是Student类或其子类对象:', isinstance(stu, Student))

""" 输出结果如下:
stu是Person类或其子类对象: True
stu是Person类或其子类对象: True
"""
	print('f是Person类或其子类对象:', isinstance(f, Person))
    print('student是Person类的子类:', issubclass(Student, Person))
    print('Flower是Person类的子类:', issubclass(Flower, Person))
    
"""输出结果如下:
f是Person类或其子类对象: False
student是Person类的子类: True
Flower是Person类的子类: False
"""
	print('stu是Student类:', type(stu)==Student())
'''
stu是Student类: False
'''

类方法和静态方法

类方法是指使用@classmethod修饰的方法,其第一个参数是类本身(而不是类的实例对象)。
类方法的特点是既可以通过类名直接调用,也可以通过类的实例对象调用。

class Complex:
    def __init__(self, real=0, image=0):
        self.real = real
        self.image = image
        
    @classmethod
    def add(cls,c1,c2):  # 定义类方法add,实现两个复数的加法运算。第一个参数cls指类本身,默认名称为cls。
        print(cls)  # 输出类方法add的第一个参数,从输出结果中可以看到cls是Complex类。
        c=Complex()
        c.real=c1.real+c2.real # 实部相加
        c.image=c1.image+c2.image # 虚部相加
        return c
if __name__ == '__main__':
    c1=Complex(1,2.5)
    c2=Complex(2.2,3.1)
    c=Complex.add(c1,c2)  # 直接使用类名调用类方法add,
    ''' 也可以使用实例对象调用。
    c=c1.add(c1,c2)或c=c2.add(c1,c2)或c=Complex().add(c1,c2)
    '''
    print('c1+c2的结果为%.2f+%.2fi'%(c.real,c.image))
  
<class '__main__.Complex'>
c1+c2的结果为3.20+5.60i

动态扩展类与实例和__slots__变量

Python作为一种动态语言,除了可以在定义类时定义属性和方法外,还可以动态地为已创建的对象绑定新的属性和方法。
在给对象绑定方法时,需要使用types模块中的MethodType方法。
注意:给一个对象绑定方法后,只能通过该对象调用该方法,其他未绑定该方法的对象则不调用。下面示例中,没有为stu2对象绑定SetName方法,因此取消注释会报错。而为Student类绑定了SetSno方法,则该类中的所有实例对象都有该方法。

MethodType(SetName,stu1) # 第一个参数是要绑定的函数名,第二个参数是绑定的对象名。
from types import MethodType
class Student:
    pass
# 注意:以下两个函数是在类外部定义的。
def SetName(self,name):
        self.name = name
        
def SetSno(self,sno):
        self.sno = sno
        
if __name__=='__main__':
    stu1=Student()
    stu2=Student()
    stu1.SetName=MethodType(SetName,stu1)    # 为对象stu1绑定SetName方法
    Student.SetSno()=SetSno	 # 为Student类绑定了SetSno方法,则该类中的所有实例对象都有该方法。
    stu1.SetName('李晓明')
    stu1.SetSno('1810100')
    #stu2.SetName('张刚')  # 取消注释会报错 ,因为没有为stu2对象绑定SetName方法。
    stu2.SetSno('1810101')

__slots__变量

可以限制可动态扩展的属性。只对__slots__所在类的实例对象有效。
如果子类中没有__slots__定义,则子类的实例对象可以进行任意属性的
动态扩展。
如果子类中有__slots__定义,则子类的实例对象可动态扩展的属性包括
子类中通过__slots__定义的属性和其父类中通过__slots__定义的属性。

class Person:
    __slots__ = ('name') 	 # 定义允许动态扩展的属性

class Student(Person): 		# 以Person类作为父类,定义子类Student类
    __slots__ = ('sno') 	# 定义允许动态扩展的属性

class Postgraduate(Student):  # 未定义__solts__属性,因此可以任意扩展属性。
    pass

if __name__ == '__main__':
    stu=Student()
    stu.sno='1810100' 	 # 为stu对象动态扩展属性sno
    stu.name='李晓明' 	 # 为stu对象动态扩展属性name
    # stu.tutor='马红'   # 取消前面的注释运行会报错,因为在Student类与父类Person中通过__solts__方法限制仅可动态扩展name和sno属性。
    pg=Postgraduate()   
    pg.sno='1810101' 	# 为pg对象动态扩展属性sno
    pg.name='张刚'   	# 为pg对象动态扩展属性name
    pg.tutor='马红'   	# 为pg对象动态扩展属性tutor
  • 14
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python学习笔记PDF是一种学习Python编程语言的资料形式,它包含了Python的基本语法、数据类型、流程控制、函数、模块、面向对象编程、异常处理等相关内容。以下是关于Python学习笔记PDF的详细内容说明: 1. 基本语法:Python学习笔记PDF中,首先介绍了Python的基本语法,例如如何定义变量、数据类型的使用(包括整数、浮点数、字符串、列表、元组、字典等),以及如何进行算术运算、比较运算和逻辑运算。 2. 流程控制:Python学习笔记PDF中,进一步介绍了流程控制的知识,包括条件判断和循环控制。条件判断主要是通过if语句进行判断执行不同的代码块,而循环控制则通过while循环和for循环来实现重复执行一段代码。 3. 函数:Python学习笔记PDF中,对函数的概念和使用进行了详细的解释。函数是代码的封装和组织方式,通过定义函数可以提高代码的重用性和可读性。学习者将了解到如何定义函数、调用函数、函数参数的传递以及函数返回值的使用。 4. 模块:Python学习笔记PDF中,介绍了Python中的模块和包的概念。模块是一组函数、类或变量的集合,以.py文件的形式存在,可以被其他程序调用和使用。学习者将学习如何导入模块、使用模块中的函数和变量。 5. 面向对象编程:Python学习笔记PDF中,对面向对象编程进行了系统的讲解。面向对象编程是一种以对象为基本单位的编程思想,通过定义类和对象,可以更好地组织和管理代码。学习者将了解如何定义类、创建对象、封装、继承和多态的使用。 6. 异常处理:Python学习笔记PDF中,对异常处理进行了介绍。异常是程序在运行过程中出现的错误,通过捕获和处理异常,可以更好地控制程序的执行流程并提高程序的健壮性。学习者将了解到如何使用try-except语句来捕获和处理异常。 总之,Python学习笔记PDF是一份全面而详细的学习Python编程语言的资料,通过学习该资料,学习者将获得扎实的Python编程基础,并能够运用Python进行简单的程序开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值