23. 面向对象

80 阅读7分钟

一,概念理解

面向对象是相对于面向过程来说的,程序可以说是算法+数据两部分组成,面向过程会偏向于算法,而面向对象会偏向于数据。

在要实现某个功能,面向对象和面向过程的区别?

  • 面向过程:是去想从开始到结束应该有哪些连续的步骤,把任务分解成一个个带参数的函数,然后再去执行这些函数
  • 面向对象:是去分析参与问题的有哪些实体,把事物抽象成对象的概念,通过调用这些实体的属性和方法解决问题

python属于典型的面向对象的编程语言,比较典型的如前面各数据类型的操作方法,它是通过类和对象的方法来组织代码的完成,而不是像面向过程语言那样直接调用函数,像调用int()其实也是类的实例化过程

二,类的概念与定义

如在学校中有学生和老师两类人,这两类人有各自的身高、体重、年龄等这类属性,也有各自的平时要做的事,如讲课、上课、写作业、批改作业等。

类似的,在python里面也定义了类

  • 类:具有相同属性和方法的对象的集合。
  • 对象:对象就是类的实例。对象有属性和方法
  • 方法:就是类中定义的函数
  • 属性:包含类属性和实例属性,类属性就是类中所有对象共有的属性,实例属性是实例化对象的属性;同名时实例对象优先调用实例属性

那么在python里面如何定义学生和老师这两类人呢

1,使用class定义一个类名,如下,定义Student(一般首字母大写)类

class Student:
    pass

2,实例化,调用定义好的类,类名+()

class Student:
    pass

Student()

3,定义类的实例属性,借用魔术方法(以__开头且以__结尾的方法,会自动调用) :

  • 构造方法__new__(cls):当实例化的时候,会自动调用__new__(cls)方法,把需要实例化的类对象作为实参传给cls形参,然后__new__再根据该类对象创建一个实例对象。(默认所有类都继承objext类,而object类中有定义了__new__,所以一般在类的定义中不写也是可以的
  • 初始化方法__init__(self):再自动调用__init__(self)方法,把刚创建的实例对象作为实参传递给self形参,然后__init__再对实例对象进行属性初始化,最后再把__new__把属性初始化之后的实例对象返回。(默认所有类都继承objext类,而object类中有定义了__init__,但是没有任何属性初始化,所以在创建类的时候如果要自定义属性还是要重新自己写
class Student#实例属性定义 
'''
def __init(self,想定义的属性名1,属性名2...):
    self.属性1名称 = 想定义的属性名1 #即表示把传入的实参赋值给self.属性1名称
'''
    def __init__(self, name, age, weight): #在self后面加上你想定义的属性名称
        self.name = name #把传入的name属性值赋值给对象self.name属性,即完成类的属性定义
        self.age = age
        self.weight = weight

#实例化的时候注意传入属性对应的值
stu1 = Student('zhangsan', 14, 8)
stu2 = Student('jige', 15, 6)
print(stu1)
print(stu2)

#实例属性调用,通过实例对象去调用,修改也可以这么去改
print(stu1.name)
print(stu2.name)

输出为

<__main__.Student object at 0x000001F54BE22FD0>
<__main__.Student object at 0x000001F54BE22640>

zhangsan
jige

如上例中,即完成了一个含有name、age、weight三个属性的Student类,并且完成了‘zhangsan’和‘jige’的实例化

4,定义类属性 对于类中所有对象共有的属性,需要定义类属性

class Student:
    
    #类属性
    school = "翻斗大街中学"
 
    #实例属性
    def __init__(self, name, age, weight): #在self后面加上你想定义的属性名称
        self.name = name #把传入的name属性值赋值给对象self.name属性,即完成类的属性定义
        self.age = age
        self.weight = weight

stu1 = Student('zhangsan', 14, 8)
stu2 = Student('jige', 15, 6)
print(stu1)
print(stu2)

## 类属性调用:既可以直接用类的名称去调用,也可以用实例对象去调用;修改只能用类名称去修改
print(Student.school)
print(stu1.school)
print(stu2.school)

输出为

<__main__.Student object at 0x000001F54BE68FA0>
<__main__.Student object at 0x000001F54BE68EE0>
翻斗大街中学
翻斗大街中学
翻斗大街中学

如上例中,对于Student这个类,即定义了一个school类属性

5,定义对象方法

直接在类中定义函数,这个函数就是这个类中所有对象可调用的类方法,传参可以使用self,从而可以使用对象属性

class Student:
    
    #类属性
    school = "翻斗大街中学"
 
    #实例属性
    def __init__(self, name, age, weight): #在self后面加上你想定义的属性名称
        self.name = name #把传入的name属性值赋值给对象self.name属性,即完成类的属性定义
        self.age = age
        self.weight = weight
        
    #定义功能,传参为self形参,那么就可以使用对象属性
    def study(self):
        print(f'{self.name}是学生')
        print(f'{self.age}是他的年龄')

stu1 = Student('zhangsan', 14, 8)
stu2 = Student('jige', 15, 6)
print(stu1)
print(stu2)

#调用对象方法
stu1.study()

输出为

<__main__.Student object at 0x000001F54BE22F40>
<__main__.Student object at 0x000001F54BE22FD0>
zhangsan是学生
14是他的年龄

6,定义类方法

和对象方法的区别就传入形参需要是类属性,另外要用装饰器@classmethod来声明是定义的类方法

class Student:
    
    #类属性
    school = "翻斗大街中学"
 
    #实例属性
    def __init__(self, name, age, weight): #在self后面加上你想定义的属性名称
        self.name = name #把传入的name属性值赋值给对象self.name属性,即完成类的属性定义
        self.age = age
        self.weight = weight

    #定义类方法
    @classmethod
    def sleep(cls):
        print(f'{cls.school} will sleep')

stu1 = Student('zhangsan', 14, 8)
stu2 = Student('jige', 15, 6)
print(stu1)
print(stu2)

#调用类方法,既可以直接用类名实参,也可以用实例对象
Student.sleep()

输出为

<__main__.Student object at 0x000001F54BE22670>
<__main__.Student object at 0x000001F54BE22D90>
zhangsan是学生
14是他的年龄
翻斗大街中学 will sleep

三,面向对象的三大特性

1,封装

可以在属性或方法前面加两个下划线开头,使其变为私有属性或方法,意思就是只能在类的内部调用,不能在类的外部直接引用,但可以通过非私有方法来进行访问,如下

class Teacher:
    def __init__(self, name, age):
        self.name = name
        self.__age = age #定义age为私有属性

    #使用非私有方法访问私有属性
    def showAge(self):
        print(f'{self.name}{self.__age}岁了')
     
     
tea1 = Teacher('aji',35)
print(tea1.name)
# print(tea1.__age) #执行发现会报错说找不到此属性
tea1.showAge()

输出为

aji
aji有35岁了

2,继承

所有的类都继承object类;子类继承父类后,会拥有父类的非私有属性和方法;在程序的执行中,会先找自己的,再去找父类的

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


    def showAge(self):
        print(f'{self.name}{self.__age}岁了')

#使用Tea01继承Teacher
class Tea01(Teacher):
    pass

3,多态性

不同对象对同一消息做出不同响应,有多个类继承,并各自声明了同一个方法,那么在调用不同类同一个方法的时候,会执行各自定义的方法逻辑,如下

class Animal:  
def speak(self):  
pass  
  
class Dog(Animal):  
def speak(self):  
return "汪汪!"  
  
class Cat(Animal):  
def speak(self):  
return "喵喵!"  
  
def animal_speak(animal):  
print(animal.speak())  
  
dog = Dog()  
cat = Cat()  
  
animal_speak(dog) # 输出 "汪汪!"  
animal_speak(cat) # 输出 "喵喵!"

在这个例子中,定义了一个父类 Animal 和两个子类 Dog 和 Cat,它们都实现了 speak() 方法。在 animal_speak() 函数中,传入任意一个 Animal 类型的对象,都会调用该对象的 speak() 方法并输出结果。在实例化 Dog 和 Cat 对象后,分别调用了它们的 speak() 方法,输出了不同的声音,这就是多态。