今天开始学习第四章面向对象了
数据类型——类——存储什么数据 变量——对象——实际存储数据
变量——属性——保存哪些数据 函数——方法——一个类支持哪些操作
类的定义
class Student:#定义了一个类
pass#什么也不执行
if __name__=='__main__':
stu=Student()#定义类中一个对象
print(stu)
#stu是Student的一个对象,这个对象所占的内存空间的首地址
<__main__.Student object at 0x000001F93F055DE0>
# 类属性定义及其访问
class Student:#定义一个类
name='Unknown'#初始属性name为Unknown
if __name__=='__main__':
print('第4行输出:',Student.name)#访问Student的属性并输出
stu1=Student()#定义对象stu1
stu2=Student()#定义对象stu2
print('第7行输出:stu1 %s stu2 %s'%(Student.name,Student.name))#没有为对象的属性赋过值,则对象的属性与类的属性一致
Student.name='未知'#重新定义类的属性为‘未知’
print('第9行输出:',Student.name)
print('第10行输出:stu1 %s stu2 %s'%(stu1.name,stu2.name))#两个对象的属性跟着类的属性变化而变化
stu1.name='wang'#定义对象stu1的属性为‘wang’
stu2.name='li'#定义对象stu2的属性为‘li’
print('第13行输出:',Student.name)#对类中对象属性值更改并不会改变类的属性值
print('第14行输出stu1 %s stu2 %s'%(stu1.name,stu2.name))#对两个对象的属性进行了重新定义,所以发生改变
Student.name='学生'#对类的属性重新定义
print('第16行输出:',Student.name)
print('第17行输出:stu1 %s stu2 %s'%(stu1.name,stu2.name))#为对象的属性赋过值,则该属性与类的属性相互独立
第4行输出: Unknown 第7行输出:stu1 Unknown stu2 Unknown 第9行输出: 未知 第10行输出:stu1 未知 stu2 未知 第13行输出: 未知 第14行输出stu1 wang stu2 li 第16行输出: 学生 第17行输出:stu1 wang stu2 li
# 为对象动态绑定新属性
class Student:#定义类
name='Unknown'#初始属性
if __name__=='__main__':
stu1=Student()#定义两个对象
stu2=Student()
stu1.age=19#为对象stu1动态绑定新的属性age
print('stu1姓名:%s,年龄:%d'%(stu1.name,stu1.age))#访问对象stu1的两个属性
#print('stu2年龄:',stu2.age)没有定义stu2的age属性
#print('使用类名访问年龄属性:'Student.age)Student的属性只有name
stu1姓名:Unknown,年龄:19
# 类中普通方法定义及调用,方法分为普通方法与内置方法,内置方法会在特定情况下由系统自动执行
class Student:#定义类
name='Unknown'#定义name属性
def SetName(self,newname):#定义方法SetName
self.name=newname#把self所在实例对象中的name属性赋为newname
def PrintName(self):
print('姓名:%s'%self.name)
if __name__=='__main__':
stu1=Student()#定义对象
stu2=Student()
stu1.SetName('li')#调用方法SetName,self在实例对象stu1中,stu1中name属性赋值为newname:li
stu2.SetName('ma')
stu1.PrintName()#stu1对象中调用方法PrintName
stu2.PrintName()
#Student.SetName('未知')报错,普通方法必须通过实例对象调用,不能通过类名调用
#Student.PrintName()
姓名:li 姓名:ma
# 私有属性:__属性名,类外访问必须在私有属性前加‘_类名’
class Student:#定义类
name='未知'
__id='未知'#定义私有属性
def SetInfo(self,newname,newid):#定义方法SetInfo
self.name=newname
self.__id=newid
def PrintInfo(self):
print('姓名:%s,身份证号:%s'%(self.name,self.__id))#类定义结束
if __name__=='__main__':
stu1=Student()#定义对象
stu1.SetInfo('li',100)#stu1调用方法SetInfo,使得stu1中name属性为li,__id属性为100
stu1.PrintInfo()#stu1调用方法PrintInfo
#print('身份证号%s'%stu1.__id)报错,因为类外不能用对象直接引用私有属性,改为
print('身份证号%s'%stu1._Student__id)#在类外引用私有属性,必须在私有属性前加上 _类名
print('姓名:',stu1.name)#类外可以直接引用普通属性
姓名:li,身份证号:100 身份证号100 姓名: li
class Student:
name='未知'
__id='未知'#私有属性
def SetInfo(self,newname,newid='unknown'):#方法与函数对应,所以里面的参数可以设置默认值
self.name=newname
self.__id=newid
def PrintInfo(self):
print('姓名:%s,身份证号:%s'%(self.name,self.__id))#类中调用私有属性不用在私有属性前加‘_类名’
if __name__=='__main__':
stu1=Student()#定义对象
stu1.SetInfo('li')#默认newid为unknown,调用方法
stu1.PrintInfo()
姓名:li,身份证号:unknown
# 构造方法,内置方法之一,在特定情况:创建一个类的对象时下自动执行
class Student:#定义类
def __init__(self):#定义构造方法
print('构造方法被使用')
self.name='未知'
def PrintInfo(self):
print('姓名:%s'%self.name)
if __name__=='__main__':
stu=Student()#创建类时自动执行__init__(self)方法,输出构造方法被使用,self实例对象stu,即stu的name属性为未知
stu.PrintInfo()
构造方法被使用 姓名:未知
class Student:
def __init__(self,name='未知'):#定义有默认参数的构造方法
print('构造方法被调用')
self.name=name
def PrintInfo(self):
print('姓名:',self.name)
stu1=Student()#定义类中对象,构造方法被使用,stu1的name属性赋值为name,默认为未知
stu2=Student('li')
stu1.PrintInfo()
stu2.PrintInfo()
构造方法被调用 构造方法被调用 姓名: 未知 姓名: li
析构方法:内置方法,__del__,局部变量作用域结束、使用del删除对象、程序结束时所有对象都被销毁,这三种情况析构方法自动调用
class Student:#定义类
def __init__(self,name):#定义构造方法
self.name=name
print('姓名为%s的对象被创建'%self.name)
def __del__(self):#定义析构方法
print('姓名为%s的对象被销毁'%self.name)#定义类结束
def func(name):#定义函数func
stu=Student(name)#创建对象,由于这是定义函数没有调用,所以什么也不输出
if __name__=='__main__':
stu1=Student('li')#定义对象,构造方法自动调用,stu1中name属性定义为li,输出创建
stu2=Student('ma')#输出创建
stu3=stu2#将stu2这个对象赋给stu3
del stu2#删除stu2,对象Student(‘ma’)还存在与stu3中,所以不输出
func('zhang')#一个对象,其实是函数被调用,输出创建,局部变量作用域结束了,输出销毁
del stu3#Student(‘ma’)被删干净了,输出销毁
stu4=Student('liu')#liu创建,程序结束,所有变量销毁
姓名为li的对象被创建
姓名为ma的对象被创建
姓名为zhang的对象被创建
姓名为zhang的对象被销毁
姓名为ma的对象被销毁
姓名为liu的对象被创建
姓名为li的对象被销毁
姓名为liu的对象被销毁
# 常用内置方法:__str__:调用python内置函数format()、print()时自动调用,返回字符串
class 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(4.2,7.5)#定义对象,__init__方法自动调用
print(c)#__str__方法自动调用
4.2+7.5i
比较运算的内置方法
__gt__(self,other)进行self>other时自动调用
__lt__(self,other)进行self<other时自动调用
__ge__(self,other)进行self>=other时自动调用
__le__(self,other)进行self<=other时自动调用
__eq__(self,other)进行self==other时自动调用
__ne__(self,other)进行self!=other时自动调用
class Student:
def __init__(self,name,age):#构造方法
self.name=name
self.age=age
def __le__(self,other):#self<=other
return self.age<=other.age
if __name__=='__main__':
stu1=Student('wang',22)#定义对象,__init__方法被调用
stu2=Student('li',11)#定义对象,__init_-方法被调用
print('wang的年龄小于等于li的年龄:',stu1<=stu2)#有比较<=,__le__被调用
wang的年龄小于等于li的年龄: False
# 继承:子类拥有父类的属性,方法
class Person:#定义类
def SetName(self,name):#方法
self.name=name#属性
class Student(Person):#person类的子类
def SetSno(self,sno):#增加方法
self.sno=sno#增加属性
class Teacher(Person):#person类的子类
def SetTno(self,tno):
self.tno=tno
class TA(Student,Teacher):#两个类student,teacher共同的子类
def SetTeacher(self,teacher):
self.teacher=teacher
if __name__=='__main__':
stu=Student()#定义类Student中的对象
stu.SetSno('1919191')#类Student中有方法SetSno,调用方法SetSno,stu的sno属性定义为sno=1919191
stu.SetName('wang')#类Student继承父类Person中的方法SetName中的方法SetName,故可以调用
print('学号:%s,姓名:%s'%(stu.sno,stu.name))
t=Teacher()#定义类Teacher中的对象
t.SetTno('90909090')#调用方法SetTno
t.SetName('li')#Teacher是Person的子类,继承父类的方法,故可以调用
print('教工号:%s,教师名:%s'%(t.tno,t.name))
学号:1919191,姓名:wang 教工号:90909090,教师名:li
# 方法重写和鸭子类型
class Person:#定义类
def __init__(self,name):#构造方法
self.name=name#属性
def PrintInfo(self):#普通方法
print('姓名:%s'%self.name)
class Student(Person):#子类
def __init__(self,sno,name):#构造方法
self.sno=sno
self.name=name
def PrintInfo(self):#普通方法
print('学号:%s,姓名:%s'%(self.sno,self.name))
def PrintPersonInfo(person):#定义函数
print('PrintPersonInfo函数中输出结果',end='#')
person.PrintInfo()
if __name__=='__main__':
p=Person('li')#Person类中的对象
stu=Student('191919','li')#Student类中的对象
p.PrintInfo()#对象p调用方法PrintInfo
stu.PrintInfo()#对象stu调用方法PrintInfo
PrintPersonInfo(p)#调用12行函数
PrintPersonInfo(stu)#调用12行函数
姓名:li
学号:191919,姓名:li
PrintPersonInfo函数中输出结果#姓名:li
PrintPersonInfo函数中输出结果#学号:191919,姓名:li
class Person:#定义类
def CaptureImage(self):#定义方法
print('Person类中的CaptureImage方法被调用')
class Camera:
def CaptureImage(self):#定义方法,只是名字相同,但这是两个不相关的函数
print('Camera类中的CaptureImage方法被调用')
def CaptureImageTest(arg):#定义了一个函数,传递实参前其参数类型不确定
arg.CaptureImage()
if __name__=='__main__':
p=Person()#定义对象
c=Camera()#定义对象
CaptureImageTest(p)#调用第7行函数
CaptureImageTest(c)
Person类中的CaptureImage方法被调用 Camera类中的CaptureImage方法被调用
# 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#pg的sno属性赋值为sno
class Postgraduate(Student):
def __init__(self,sno,name,tutor):
print('Postgraduate类构造方法被调用')
super().__init__(sno,name)#调用父类构造方法
self.tutor=tutor#self对应对象tutor属性值赋值为tutor
if __name__=='__main__':
pg=Postgraduate('1919919','li','ma')#Postgraduate类中的对象
print('学号%s,姓名%s,教师%s'%(pg.sno,pg.name,pg.tutor))
Postgraduate类构造方法被调用 Student类被调用 Person类构造方法被调用 学号1919919,姓名li,教师ma
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#pg的sno属性赋值为sno
class Postgraduate(Student):
def __init__(self,sno,name,tutor):
print('Postgraduate类构造方法被调用')
super(Postgraduate,self).__init__(sno,name)#调用父类构造方法
self.tutor=tutor#self对应对象tutor属性值赋值为tutor
if __name__=='__main__':
pg=Postgraduate('1919919','li','ma')#Postgraduate类中的对象
print('学号%s,姓名%s,教师%s'%(pg.sno,pg.name,pg.tutor))
Postgraduate类构造方法被调用 Student类被调用 Person类构造方法被调用 学号1919919,姓名li,教师ma
# 内置函数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))
print('f是Person类或其子类对象',isinstance(f,Person))
print('Student是Person类的子类',issubclass(Student,Person))
print('Flower是Person类的子类',issubclass(Flower,Person))
print('stu对象所属的类',type(stu))
print('f对象所属的类',type(f))
print('stu是Person类对象',type(stu)==Person)
print('stu是Student类对象',type(stu)==Student)
stu是Person类或其子类对象: True stu是Student类或其子类对象 True f是Person类或其子类对象 False Student是Person类的子类 True Flower是Person类的子类 False stu对象所属的类 <class '__main__.Student'> f对象所属的类 <class '__main__.Flower'> stu是Person类对象 False stu是Student类对象 True
# 类方法@classmethod与静态方法@staticmethod
class Complex:
def __init__(self,real=0,image=0):
self.real=real
self.image=image
@classmethod#定义类方法add
def add(cls,c1,c2):
print(cls)#类方法第一个变量为类本身Complex
c=Complex()
c.real=c1.real+c2.real
c.image=c1.image+c2.image
return c
if __name__=='__main__':
c1=Complex(1,1.2)
c2=Complex(2.2,6.4)
c=Complex.add(c1,c2)#直接使用类名调用类方法add,普通方法只能通过实例对象调用
print('c1,c2的和为%.2f+%.2f'%(c.real,c.image))
<class '__main__.Complex'> c1,c2的和为3.20+7.60
class Complex:
def __init__(self,real=0,image=0):
self.real=real
self.image=image
@classmethod#定义类方法add
def add(cls,c1,c2):
print(cls)#类方法第一个变量为类本身Complex
c=Complex()
c.real=c1.real+c2.real
c.image=c1.image+c2.image
return c
if __name__=='__main__':
c1=Complex(1,1.2)
c2=Complex(2.2,6.4)
c=c1.add(c1,c2)#也可以通过实例对象调用:c=c2.add(c1,c2),c=Complex().add(c1,c2)
print('c1,c2的和为%.2f+%.2f'%(c.real,c.image))
<class '__main__.Complex'> c1,c2的和为3.20+7.60
class Complex:
def __init__(self,real=0,image=0):
self.image=image
self.real=real
@staticmethod#定义静态方法add
def add(c1,c2):#与类方法不同的是静态方法不需要第一个为所在类的类参数
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,4.4)
c=Complex.add(c1,c2)#通过类直接调用静态方法
print('c1,c2的和为%.2f+%f'%(c.real,c.image))
c1,c2的和为3.20+6.900000
# 动态扩展类和__slots__变量
from types import MethodType#从types模块引方法
class Student:
pass
def SetName(self,name):#定义函数
self.name=name
def SetSno(self,sno):
self.sno=sno
if __name__=='__main__':
stu1=Student()#定义Student对象
stu2=Student()
stu1.SetName=MethodType(SetName,stu1)#stu1定义新方法SetName。MethodType(方法名,对象名)
Student.SetSno=SetSno#为类定义新方法
stu1.SetName('li')#对象stu1有SetName方法
stu1.SetSno('191991')#类有方法SetSno,所以对象stu1可以引用方法SetSno
#stu2.SetName('zhang'),stu2没有SetName方法
stu2.SetSno('181818')#类有方法SetSno,所以对象stu2可以引用方法SetSno
print(stu1.name,stu1.sno,stu2.sno)
li 191991 181818
#__slots__:限制可动态扩展的属性
class Person:
__slots__=('name')#类Person中的对象的属性只能为name
class Student(Person):
__slots__=('sno')
class Postgraduate(Student):
pass
if __name__=='__main__':
stu=Student()#stu为子类Student的对象
stu.sno='1919191'#子类Student中属性可以为sno,也可以为其父类中属性name
stu.name='li'
#stu.tutor='ma'。stu在类Student中属性只能为name,sno
pg=Postgraduate()#pg为类Postgraduate中的对象,可以随意定义新属性
pg.sno='171717'
pg.name='zhang'
pg.tutor='ma'
# @property装饰器
import datetime#后面用到datetime包
class Student:
@property#定义一个获取(getter)属性score值的方法
def score(self):
return self._score#在getter和setter中访问一个属性,需要在属性前加下划线
@score.setter#对属性score设置(setter)一个值,@属性名.setter
def score(self,score):
if score<0 or score>100:
print('成绩必须在0~100')
else:
self._score=score#为属性score赋值为score
@property#定义一个获取属性age值的方法,没有setter设置值得方法,所以该属性是只读属性,不能设置该属性的值
def age(self):
return datetime.datetime.now().year-self.birthday
if __name__=='__main__':
stu=Student()#stu为类Student的一个对象
stu.score=80#stu在类Student中,有属性score,且可以赋值
stu.birthday=2000#为对象stu定义属性值
print('年龄%d,成绩%.2f'%(stu.age,stu.score))
#stu.age=19。age属性只读,不能赋值
stu.score=105
print('年龄%d,成绩%.2f'%(stu.age,stu.score))
年龄23,成绩80.00 成绩必须在0~100 年龄23,成绩80.00