【10月更文挑战第13天】
面向过程和面向对象
面向过程:
变量和函数。 “散落” 在文件的各个位置,甚至是不同文件中。
看不出变量与函数的相关性,非常不利于维护,设计模式不清晰。
经常导致程序员,忘记某个变量的相关性,而导致无法检测的错误
面向过程:
相关的变量和函数都“封装” 在对象里,以对象为单位来管理代码。
变量与函数的相关性清晰,利于维护,设计模式清晰。
程序员可以配合“继承” 来提高代码的可重用性,加强合作开发。
区分
面向过程的变成侧重点于编写一系列的步骤来解决问题
面向对象的变成侧重于创建对象和类,这些对象和类封装了数据和处理这些数据的方法
下面我将通过一个简单的例子来展示这两种编程范式的区别。假设我们要编写一个程序,用于计算一个矩形的面积。
面向过程的编程(C语言示例)
在面向过程的编程中,我们通常直接编写函数来执行特定的任务。
#include <stdio.h>
// 定义一个函数来计算矩形的面积
int calculateRectangleArea(int length, int width) {
return length * width;
}
int main() {
int length, width;
// 获取用户输入
printf("请输入矩形的长度: ");
scanf("%d", &length);
printf("请输入矩形的宽度: ");
scanf("%d", &width);
// 调用函数计算面积
int area = calculateRectangleArea(length, width);
// 输出结果
printf("矩形的面积是: %d\n", area);
return 0;
}
在这个C语言的例子中,我们定义了一个函数calculateRectangleArea
来计算面积,然后在main
函数中获取用户输入并调用这个函数。
面向对象的编程(Python示例)
在面向对象的编程中,我们创建类来封装数据和行为。
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def calculate_area(self):
return self.length * self.width
# 创建矩形对象
rectangle = Rectangle(5, 3)
# 调用方法计算面积
area = rectangle.calculate_area()
# 输出结果
print(f"矩形的面积是: {area}")
在这个Python的例子中,我们定义了一个Rectangle
类,它有两个属性(length和width)和一个方法(calculate_area)。我们创建了一个Rectangle
对象,并调用其方法来计算面积。
主要区别
封装:面向对象编程通过类来封装数据和方法,而面向过程编程通常不封装数据和函数。
可重用性:面向对象编程通过继承和多态性提高了代码的可重用性。
维护性:面向对象编程通常更容易维护,因为每个对象都是独立的单元。
抽象:面向对象编程提供了更好的抽象,通过类和对象隐藏了实现细节。
这些例子展示了两种编程范式的基本思想,但在实际应用中,它们可以更加复杂和多样化。
就我总结:python中我们直接调用函数,不会像是c语言那么复杂一个一个进行定义
面向对象的介绍
借鉴函数的封装思维,再次对函数和变量进行封装,来提高代码的复用性。用关键字 class 定义,为了便于区分,把的代码块称为 类。
我们使用类将函数和变量进行封装 ,我们使用class这个关键字进行封装
变量就是属性,函数就是方法
'''
class 类名:
属性\方法
属性:变量()
方法:函数()
'''
#定义一个人类
class Person:
name='小明' #类属性
def work():#类方法
print(f'{Person.name}的工作是厨师')
#这里的name 是类属性我们需要通过类名进行调用
#变量是属性,函数是方法
#上面我们就实现了一个类的创建了
#类是通过对象进行实现后续的操作的
#那么我们就需要创建一个对象
#创建对象:类名()
print(Person)
#<class '__main__.Person'>
p1=Person()
print(p1)
#<__main__.Person object at 0x0196F970>
#这个p就是我们创建的对象
#我们每次创建对象编译器就会为其进行空间的分配
#一个类是可以进行多个对象的创建的
p2=Person()
#我们对于类属性和类方法的访问
#通过对象直接对类中的元素进行访问
print(p1.name)
#p1.work()
#这么写是会报错的
#对象在调用方法时,会将对象信息传递给方法
#所以我们在利用对象调用类方法的时候是传递了一个类似于指针的东西
#但是我们的函数中并没有进行接收的操作
#所以这个是会进行报错的
#所以我们在调用类方法的时候我们是不能直接通过对象进行调用的
#综上所述:
#想要调用类属性的话
#类名.属性名
print(Person.name)
#想要调用类方法的话
#类名.方法名
print(Person.work())
#小明
#小明
#小明的工作是厨师
p1.work()
这么写是会报错的
对象在调用方法时,会将对象信息传递给方法
所以我们在利用对象调用类方法的时候是传递了一个类似于指针的东西
但是我们的函数中并没有进行接收的操作
所以这个是会进行报错的
那么我们如何通过这个对象进行类方法的调用呢?
我们在这个类方法中添加一个参数self用来接收传过来的对象信息
那么我们就能进行调用了
这种在类函数中添加self的操作叫做实例方法
哪个对象调用它,它就接收哪个对象的信息
所以self==对象本身
所以我们在类里面我们用self代表对象,在外面就用对象代表对象
类方法和实例方法的区别在于括号中是否存在self
只有调用示例化的方法我们才用创建对象
我们的方法基本上都是用实例方法
实例方法我们只能通过对象名进行调用
对于没有添加self的类方法我们只能够通过类名进行调用
每次通过类名进行类方法的调用这个里面的值都是固定的
但是我们通过这个实例方法进行调用的话,那么我们这个里面的值就随着对象的改变而改变
class Person:
name='小明' #类属性
def work():#类方法
print(f'{Person.name}的工作是厨师')
def job(self):#实例方法
print(f'self:{self}')
p1=Person()
p1.job()
#<__main__.Person object at 0x03C29AB0> 这个就是对象的地址了
#我们只要将类中的方法实例化我们就能通过对象进行类方法的调用了
#我们在类方法中定义了self用来接受传过来的对象信息
总结下:类方法只能通过类名进行调用,每次调用的结果都是一样的,而且类方法是不能通过对象进行调用的,因为我们在调用类方法的时候通常是会在函数中传递实参的,但是我们的类函数中并没有形参进行接收,那么就会造成报错的现象,但是我们的实例方法中,我们在原本的类函数的基础上添加了self这个参数用来接受对象的信息的,那么在这个实例方法中我们就有形参进行接收调用函数时传过来的对象信息了,我们在外面通过对象进行对象的访问,但是在这个实例方法中我们通过self进行访问对象,因为self指向的是对应的对象
实例方法是可以根据对象的不同而导致传递的值就不痛,就不会像类方法那么固定了
通过实例方法的话我们函数中的参数随着 对象的变化进行变化
实例化对象的介绍
假如我们现在有三个人,我们分别调用这个实例方法,我们都是不会相互影响的,因为三个人的self都是不同的,不会互相影响,这个就是实例方法的好处
如果想使用类方法的话,那么所有的对象都是一样的东西
学到这里我们就理解这个类方法和实例方法的区别了
class Mode:#模型类
#类方法:对于所有实例对象统一的功能
def mode():
print("这是一个苹果15手机壳模型")
#实例方法:应用于对象,对于对象不同,内容不同
def types(self0,color,mat):
print(f"这是一个{color}颜色{mat}材质的手机壳")
#调用类方法
Mode.mode()#类名.类方法进行调用
#这是一个苹果15手机壳模型
#调用示例方法:实例对象.实例方法()
#创建实例对象
m1=Mode()
m1.types("红色","金属")
#这是一个红色颜色金属材质的手机壳
类中除了属性和方法还有个占位符pass:
'''
class 类名:
属性/方法/pass
属性--变量
方法--函数
pass--占位符
我们在定义类的时候我们对于类中需要写什么我们还没有想好,
我们可以通过pass进行占位的操作的
'''
class Pub:
pass#进行占位
#这么就不会出现报错,但是我们如果不加pass的话,并且类中是空的,那么就会报错
如果我们没有想好类里面写什么的话,使用pass进行占位置,这样这个类就不会报错了
类的使用---实例化对象:类名
class Student:
pass
print(Student)
#<class '__main__.Student'>
s1=Student()
print(s1)
#<__main__.Student object at 0x0184F090>
类方法:用于共享的操作,所有对象是一致的
实例方法:用于不同的对象有不同的数据
定义实例属性:在实例方法中通过self.属性名=值
实例属性一但被定义了,那么在实例方法中都能进行调用的
不存在之前函数内变量的局部域和全局域的说法
只要是实例方法的话就能进行实例属性的运用
class Student:
#姓名、年龄、成绩---描述----属性
def fun(self,name,age,grade):#接收传入的数据
self.name=name
self.age=age
self.grade=grade
#睡觉、吃饭、学习---动作、行为---方法 def 方法名()
#self接受对象信息,即seif=对象
def sleep(self):
print(f'{self.name}正在睡觉')
#在类里面进行实例属性的调用
def eat(self):
print(f'{self.name}正在吃东西')
def study(self):
print(f'{self.name}正在学习')
s1=Student()
s1.fun("小明",12,78)
#现在fun函数里面有四个参数,第一个self我们是不用传实参的
#self是可以自动传参的,不需要手动传参的
print(s1.age)
s1.sleep()
#小明正在睡觉
'''
实例属性一但被定义了,那么在实例方法中都能进行调用的
不存在之前函数内变量的局部域和全局域的说法
只要是实例方法的话就能进行实例属性的运用
'''
s1.eat()
#小明正在吃东西
s1.study()
#小明正在学习
'''
s2=Student()
s2.sleep()
这么写是会报错的,因为我们是没有进行对象内属性的初始化的
'''
#生成多个对象,每个对象的值都是不一样的
#我们在调用其他的实例方法的之前我们一定要对对象里面的属性进行初始化
#不然后面的方法是调用不了的
我们直接使用对象名.实例方法名()进行类中的实力方法进行调用
对于上面的代码,如果我们又创建了一个对象s2,但是没有调用fun函数进行初始化,那么我们就是不能进行后面的实力函数的调用的
因为fun函数内的实力属性都没有被定义
我们需要将实例属性定义之后才能进行后续的实力属性的调用操作的