2022.11.10~2022.11.11
1.面向对象的三大特征:封装、继承、多态
2.封装
# 封装
class Car:
def __init__(self,brand):
self.brand=brand
def start(self):
print('汽车以启动...')
car=Car('宝马X5')
car.start()
print(car.brand) # 在类的外部使用类封装的属性和方法
class Student:
def __init__(self,name,age):
self.name=name
self.__age=age # 年龄不希望在类的外部被使用,所以加了两个_
def show(self):
print(self.name,self.__age) # age可以在类的内部使用
stu=Student('张三',20)
stu.show() # 张三 20
# 在类的外部使用name与age
print(stu.name)
# print(stu.__age) # AttributeError: 'Student' object has no attribute '__age'
# 不希望在类的外部使用,但是可以使用
print(dir(stu)) # 可以看到stu中的属性与方法 '_Student__age'
print(stu._Student__age) # 20 在类的外部可以通过 _Student__age 进行访问 不希望被访问--靠自觉性
3.继承
# 继承
class Person(object): # Person继承object类,也可以不写
def __init__(self,name,age):
self.name=name
self.age=age
def info(self):
print(self.name,self.age) # Person类定义完成
class Student(Person): # 定义了一个Person的子类
def __init__(self,name,age,stu_no):
super().__init__(name,age) # 使用super调用父类的__init__方法,把name和age传入
self.stu_no=stu_no # 使用self——Student类的对象,将学号赋值
# 学生类就定义完成了
class Teacher(Person):
def __init__(self,name,age,teachofyear):
super().__init__(name,age) # 调用父类
self.teachofyear=teachofyear
stu=Student('张三',20,'1001')
teacher=Teacher('李四',34,10)
stu.info() # 调用info方法--从Person类继承来的方法
teacher.info()
'''多继承'''
class A(object):
pass
class B(object):
pass
class C(A,B):
pass
①方法重写
'''①方法重写'''
class Person(object): # Person继承object类,也可以不写
def __init__(self,name,age):
self.name=name
self.age=age
def info(self):
print(self.name,self.age) # Person类定义完成
class Student(Person):
def __init__(self,name,age,stu_no):
super().__init__(name,age)
self.stu_no=stu_no
def info(self): # 重写父类的方法
super().info() # 还想使用父类的方法,通过super().info()调用父类中被重写的那个方法
print(self.stu_no) # 在Student类中重写方法 这里程序会先执行父类中的输出,然后在执行子类中的输出
class Teacher(Person):
def __init__(self,name,age,teachofyear):
super().__init__(name,age) # 调用父类
self.teachofyear=teachofyear
def info(self):
super().info()
print('教龄',self.teachofyear)
stu=Student('张三',20,'1001')
print('------------------')
teacher=Teacher('李四',34,10)
stu.info()
teacher.info()
②object类
# object类1
class Student:
pass
stu=Student() # 创建Student类的对象
print(dir(stu))
'''-->这些属性和方法都是从父类object类中继承而来的,可以进行使用的:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__','__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__','__subclasshook__', '__weakref__']'''
print(stu) # 输出了对象的内存地址--<__main__.Student object at 0x0000025878ACA400>
# object类2
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return '我的名字是{0},今年{1}岁'.format(self.name,self.age) # 输出属性值
stu=Student('张三',20)
print(dir(stu))
print(stu) # 我的名字是张三,今年20岁 不会再输出对象的内存地址,因为一旦重写str后,将不再输出对象的内存地址,而是调用str函数,输出里面的内容
'''print(stu) 默认会调用__str__()方法 因此上面返回了字符串内容
经常会重写__str__()方法,用于返回对对象的描述'''
print(type(stu)) # <class '__main__.Student'> Student类型
4.多态
# 多态
class Animal(object):
def eat(self):
print('动物会吃')
class Dog(Animal):
def eat(self):
print('狗吃骨头...')
class Cat(Animal):
def eat(self):
print('猫吃鱼...')
class Person:
def eat(self):
print('人吃五谷杂粮')
# 定义一个函数
def fun(obj):
obj.eat() # 调用对象的eat方法
# 开始调用函数
fun(Cat())
fun(Dog())
fun(Animal())
fun(Person())
# 不关心Person是水的子类,只关心Person是否有eat的行为
5.特殊属性和特殊方法
①特殊属性
# 特殊属性
'''print(dir(object))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
'''
# __dict__
class A:
pass
class B:
pass
class C(A,B):
def __init__(self,name,age):
self.name=name
self.age=age
# 创建C类的对象
x=C('Jack',20) # x是C类型的一个实例对象
print(x.__dict__) # 查看对象的属性字典(方法在类中,实例只负责调用)--查看该实例对象绑定了哪些属性 {'name': 'Jack', 'age': 20}
print(C.__dict__) # 类对象的属性、方法的字典 {'__module__': '__main__', '__init__': <function C.__init__ at 0x000001D8F4B4A790>, '__doc__': None}
print(x.__class__) # 输出对象所属的类 <class '__main__.C'>
print(C.__bases__) # C类的父类类型的元组 (<class '__main__.A'>, <class '__main__.B'>)
print(C.__base__) # 类的基类 哪个父类写在前面就会输出谁 C(A,B) <class '__main__.A'>
print(C.__mro__) # 类的层次结构 C继承A、继承B。继承object (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
print(A.__subclasses__()) # 子类列表 [<class '__main__.C'>]
②特殊方法
# 特殊方法
# 1.__add__()
a=20
b=100
c=a+b # 两个整数类型的对象的相加操作
d=a.__add__(b) # 底层实际上是a对象的__add__()方法和b进行运算的
print(c)
print(d)
'''两个整数类型的对象可以执行加法操作,那自定义类型的对象可以执行加法操作吗?'''
'''
class Student:
def __init__(self,name):
self.name=name
stu1=Student('张三')
stu2=Student('李四')
s=stu1+stu2
print(s) # 报错'''
'''若想执行相加操作,可以这样写'''
class Student:
def __init__(self,name):
self.name=name
def __add__(self,other):
return self.name+other.name
def __len__(self):
return len(self.name)
stu1=Student('张三')
stu2=Student('李四')
# 此时可执行相加操作:(以下两种写法均可)
s=stu1+stu2 # 实现了两个对象的加法运算(因为在Student类中 编写了__add__()特殊的方法)
print(s) # 张三李四
s=stu1.__add__(stu2)
print(s) # 张三李四
# 2.__len__()
lst=[11,22,33,44]
print(len(lst)) # 4 len是内置函数len 可以计算列表的长度
print(lst.__len__()) # 4 该特殊方法所对应的是len这个内置函数,它们的结果是相同的
'''print(len(stu1)) # 报错 这样向直接输出stu1的长度,报错,应在class Student 中写__len__()方法 '''
print(len(stu1)) # 2 写完__len__()后可得对象的长度 本例中name的长度即为对象的长度
# 3.__init__()
class Person(object):
def __new__(cls, *args, **kwargs): # __new__()用于创建对象
print('__new__被调用执行了,cls的id值为{0}'.format(id(cls)))
obj=super().__new__(cls)
print('创建的对象的id为:{0}'.format(id(obj))) # 在new中所创建的对象就是self和p1
return obj
def __init__(self,name,age): # __init__()对对象的属性初始化
print('__init__被调用了,self的id值为:{0}'.format(id(self)))
self.name=name
self.age=age
print('object这个类对象的id为:{0}'.format(id(object)))
print('Person这个类对象的id为:{0}'.format(id(Person)))
# 创建Person类的实例对象
p1=Person('张三',20)
print('p1这个Person类的实例对象的id为:{0}'.format(id(p1)))
6.类的浅拷贝与深拷贝
# 类的浅拷贝与深拷贝
class CPU:
pass
class Disk:
pass
class Computer:
def __init__(self,cpu,disk):
self.cpu=cpu
self.disk=disk
①变量的赋值操作
# 变量的赋值 两个变量指向一个对象
cpu1=CPU()
cpu2=cpu1
print(cpu1,id(cpu1)) # <__main__.CPU object at 0x000001B78D15A400> 1887857648640
print(cpu2,id(cpu2)) # 内存地址相同 <__main__.CPU object at 0x000001B78D15A400> 1887857648640
②浅拷贝
# 类的浅拷贝
disk=Disk() # 创建一个硬盘类的对象
computer=Computer(cpu1,disk) # 创建一个计算机类的对象
# 浅拷贝
import copy # 导入一个包copy
computer2=copy.copy(computer) # 拷完了
print(disk)
print(computer,computer.cpu,computer.disk) # <__main__.Computer object at 0x000002540BF78C10> <__main__.CPU object at 0x000002540BA2A400> <__main__.Disk object at 0x000002540BA09100>
print(computer2,computer2.cpu,computer2.disk) # <__main__.Computer object at 0x000002540BF88520> <__main__.CPU object at 0x000002540BA2A400> <__main__.Disk object at 0x000002540BA09100>
'''computer和computer2是不同的对象,但所包含的子对象cpu和disk内存地址相同'''
③深拷贝
# 深拷贝
computer3=copy.deepcopy(computer) # 拷完了
print(computer,computer.cpu,computer.disk) # <__main__.Computer object at 0x000001AA63448C10> <__main__.CPU object at 0x000001AA62EFA400> <__main__.Disk object at 0x000001AA62ED9100>
print(computer3,computer3.cpu,computer3.disk) # <__main__.Computer object at 0x000001AA63488DF0> <__main__.CPU object at 0x000001AA63499280> <__main__.Disk object at 0x000001AA63499250>