chap13 (python全栈开发教程)

 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>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值