Python的学习(十四):面向对象

  • Post author:
  • Post category:python




Python的学习(十四):面向对象



面向对象三大特征



封装

提高程序的安全性。

  1. 将数据(属性)和行为(方法)包装到类对象中。在方法内部对属性进行操作,在类对象的外部调用方法,这样不需要关心内部具体实现细节,从而隔离了复杂度。

    class Cardef __init__(self,brand):
            self.brand = brand
         
        def start(self):
            print('汽车已经启动。。。')
            
    car = Car('宝马X5')
    car.start()
    print(car.brand)
    
  2. 在Python中没有专门修饰符用于属性的私有,如果希望属性不在类外部被访问,前面使用两个“_”

    class Student:
        def __init__(self,name,age):
            self.name = name
            self.__age = age#年龄不希望被外部使用
        def show(self):
            print(self.name,self.__age)
            
            
    stu = Student('张三',20)
    stu.show()
    #在类的外部不能直接使用age属性
    #查看类的所有属性
    print(dir(stu))
    #可以通过_Student__age访问
    print(stu._Student__age)
    #不建议访问
    



继承

提高代码的复用性。

语法格式:

class 子类类名(父类1,父类2.....):
      pass


python支持多继承!!!!!!!!!!

如果一个类没有继承任何类,那么默认继承Object类。


定义子类时,必须在其构造函数中调用父类的构造函数。

#定义一个父类
class Person(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
    def info(self):
        print(self.name,self.age)
      
#定义一个学生子类
class Student(Person):
    def __init__(self,name,age,stu_no):
        super().__init__(name,age)
        self.stu_no = stu_no
        
#定义一个老师子类
class Teacher(Person):
    def __init__(self,name,age,teachofyear):
        super().__init__(name,age)
        self.teachofyear = teachofyear
        
        
#使用
stu = Student('张三',20,'1001')
teacher = Teacher('李四',34,10)

#可以多继承
class A:
    pass

class B:
    pass

class C(A,B):
    pass



方法重写

  • 如果子类对继承父类的某个属性或者方法不满意,可以在子类种对其(方法体)进行重新编写
  • 子类重新编写的方法可以通过**super().xxx()**调用父类中被重写的方法。
class Student(Person):
    def __init__(self,name,age,stu_no):
        super().__init__(name,age)
        self.stu_no = stu_no
        
    #重写info方法
    def info(self):
        #调用父类的方法
        super().info()
        print('学号:{0}'.format(self.score))



object类

  • object类是所有类的父类,因此所有类都有object类的属性和方法。
  • 内置函数dir()可以查看指定对象所有的属性
  • Object有一个_

    str_

    ()方法,可以用于返回一个对于对象的描述对应与内置函数str()经常用于·print()方法,帮我们查看对象信息,所以我们经常会对_str_()重写。
class Person(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age
    
    def info(self):
        print('姓名:{0},年龄:{1}'.format(self.name,self.age))
    
    #重写方法后不再输出内存地址,而是输出重写后的函数内容
    def __str__(self):
        return '姓名:{0},年龄:{1}'.format(self.name,self.age)
    
o = object()
p = Person('jack',20)
print(dir(o))
print(dir(p))
print(p)



多态


提高程序的可拓展性和可维护性!

具有多种形态,指的是:即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量引用的类型,动态决定调用哪个对象的方法。

class Animal(object):
    def eat(self):
        print('动物会吃')
        
class Dog(Animal):
    def eat(self):
        print('狗吃骨头')
        
class Cat(Animal):
    def eat(self):
        print('猫吃鱼儿')
        
class Person(object):
    def eat(self):
        print('人吃好吃的')
        
#创建一个函数
def fun(obj):
    obj.eat()
    
#调用
fun(Cat())#猫吃鱼儿
fun(Dog())#狗吃骨头
fun(Person())#人吃好吃的



多态的区别

  • 静态语言实现多态的三个必要条件

    1. 继承
    2. 方法重写
    3. 父类引用指向子类对象
  • 动态语言不需要关心对象是什么类型,只关心对象的行为



特殊的属性和方法



特殊属性

  • __dict__ :获得类对象或者实例对象所绑定的所有属性和类方法的字典。
class A:
    pass
class B:
    pass
class C(A,B):
    def __init__(self,name,age):
        self.name = name
        self.age = age

class D(A):
    pass
#创建C类的对象
c = C('Jack',20)#c是一个实例对象
print(c.__dict__)#实例对象的属性字典
print(C.__dict__)

print('----------')
print(c.__class__)#输出对象所属的类
print(C.__bases__)#C类的父类类型的元素
print(C.__base__)#离得近的父类,第一个,基类
print(C.__mro__)#类的层次结构
print(A.__subclasses__())#子类的列表

image-20220206230851230

image-20220206230930538



特殊方法

名称 描述
__len__() 通过重写,让内置函数len的参数可以是自定义类型
__add__() 通过重写,可以使用自定义对象具有“+”功能
__new__() 用于创建对象
__init__() 对创建的对象进行初始化
#add方法
a = 20
b = 100
c = a + b #两个整数可以进行相加操作
print(c)#120
d = a.__add__(b)
print(d)#120
#两个结果一致

class Student:
    def __init__(self,name):
        self.name = name
        
stu1 = Student('张三')
stu2 = Student('李四')

s = stu1 + stu2
print(s)#会报错,因为两个类型不能相加

#要是非要相加,可以重写add函数
    def __add__(self,other):
        return self.name + other.name
s = stu1.__add__(stu2)#结果和上面的相加操作一样是:张三李四
print(s)


#len方法
print('---------------')
lst = [11,22,33]
print(len(lst))
print(lst.__len__())
#两个函数的输出结果都是相同的为3

print(len(stu1))#报错,因为该对象没有长度1
#非要输出长度,重写方法
def __len__(self):
    return len(self.name)
  • new和init
class Person(object):
        
    #创建对象
    def __new__(cls,*args,**kwargs):
        print('__new__被调用了,cls的id值为{0}'.format(id(cls)))
        obj = super().__new__(cls)
        print('创建的对象id为:{0}'.format(id(obj)))
        return obj
      
      #初始化对象
      def __init__(self,name,age):
        print('__init__被调用了,self的id值为{0}'.format(id(self)))
        self.name = name
        self.age = age

#创建Person类的实例对象
p1 = Person('张三'20)
print('p1这个Person类的实例对象id是{0}'.format(id(p1)))
        
  • 首先将Person对象传给cls,id是9360
  • 然后将cls传到new函数中创建一个obj对象,id是7104
  • 将obj对象返回给self,id是7104
  • 最后将self初始化后传给p1,id还是7104

image-20220206235148317



类的浅拷贝和深拷贝



变量的赋值

  • 只是形成两个变量,实际上还是指向同一个对象
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)
print(cpu2)#两个内存地址是一样的

image-20220207003258939

实质上是同一个对象赋值给了两个变量:

image-20220207002203429



浅拷贝

  • 一般python中的拷贝都是浅拷贝,拷贝时对象包含的子对象内容不拷贝,因此,源对象和拷贝对象会引用同一个子对象。
#类的创建见上面
disk = Disk()#创建一个硬盘类对象
computer = Computer(cpu1,disk)#创建一个计算机类对象

#浅拷贝
import copy
computer2 = copy.copy(computer)
print(computer,computer.cpu,computer.disk)
print(computer2,computer2.cpu,computer3.disk)
#不是相同的对象,但是子对象是相同的

image-20220207003240102

内存解释:

image-20220207003612631



深拷贝

  • 使用deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象的子对象也不相同
computer3 = copy.deepcopy(commputer)
print(computer,computer.cpu,computer.disk)
print(computer3,computer3.cpu,computer3.disk)

image-20220207003944252

内存解释:

image-20220207004114304

image-20220207004200483



总结

image-20220207004254298



版权声明:本文为weixin_51276056原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。