作者|HIMANSHI SINGH
编译|VK
来源|Analytics Vidhya
介绍
在学习面向对象编程时,我决定深入研究它的历史,结果发现它很迷人。术语“面向对象编程”(OOP)是Alan Kay 在1966年研究生院时提出的。
Simula语言是第一种具有面向对象编程特点的编程语言。它是在1967年开发的,用于制作模拟程序,其中最重要的信息称为对象。
尽管OOPS自20世纪60年代初就在市场上,但在20世纪90年代,OOPS开始因为C++而增长。
除此之外,这种编程技术已经被包括Python在内的各种编程语言所采用,它的应用几乎遍及所有领域,如实时系统、人工智能、专家系统、CS系统、面向对象数据库等等。
因此,在本文中,我将解释Python中面向对象编程的基本概念。
目录
-
什么是面向对象编程?
-
面向对象编程(OOP)与面向过程编程(POP)
-
OOPs的主要概念
- 什么是类?
- 对象和对象实例化
- 类方法
- Python类中的继承
- 封装
- 多态性
- 数据抽象
什么是面向对象编程?
面向对象编程(OOP)就是创建“对象”。对象是一组相互关联的变量和函数。这些变量通常称为对象的属性,函数称为对象的行为。这些对象为程序提供了一个更好、更清晰的结构。
例如,汽车可以是一个对象。如果我们把汽车当作一个对象,那么它的属性就是——颜色、型号、价格、品牌等等,它的行为/函数是加速、减速、换挡。
另一个例子——如果我们把狗当作一个物体,那么它的属性就是——它的颜色、品种、名字、体重等,而它的行为/函数是行走、吠叫、玩耍等。
面向对象编程因其在编程中实现了对象、隐藏、继承等现实实体而闻名。它使可视化更容易,因为它接近真实世界的场景。
面向对象编程(OOP)与面向过程编程(POP)
OOP和过程式编程的基本区别是
-
一种思考POP的方法就是你做柠檬水的方式。制作柠檬水的过程包括——首先根据需要取水,然后在水中加入糖,然后在混合物中加入柠檬汁,最后将整个溶液混合。这样你的柠檬水就准备好了。同样,POP也需要一定的步骤。程序程序由函数组成。这意味着在POP方法中,程序被划分为特定于不同任务的函数。这些功能按特定的顺序排列,程序的控制按顺序进行。
-
而OOP程序是由对象组成的。面向对象方法将程序划分为对象。这些对象是将现实世界对象的属性和行为捆绑在一起的实体。
-
POP只适用于小任务。因为随着程序长度的增加,代码的复杂性也随之增加。最后变成了一个函数网。而且,它变得很难调试。OOP通过更清晰、以更不复杂的结构来解决这个问题。它允许以继承的形式重新使用代码。
-
另一个重要的是,在面向过程的编程中,所有函数都可以访问所有数据,这意味着缺乏安全性。假设你想保护来自世界各地的凭据或任何其他关键信息。那么程序化方法就不能为你提供这种安全性。因为这个OOP帮助你实现了一个称为封装的惊人功能,它允许我们隐藏数据。不用担心,在本文的后半部分,我将详细介绍这一点以及面向对象编程的其他概念。现在,只需理解OOP支持安全性,POP不支持。
-
编程语言如C、Pascal和Basic使用过程方法,而java、Python、JavaScript、PHP、Scala和C++是提供面向对象方法的主要语言。
OOPs的主要概念
在本节中,我们将深入探讨OOP的基本概念。我们将讨论以下主题
-
类
-
对象
-
方法
-
继承
-
封装
-
多态性
-
数据抽象
1.什么是类?
这个问题的直接答案是:类是对象的集合。与原始数据结构不同,类是用户定义的数据结构。它们使代码更易于管理。
让我们看看如何定义下面的类
class class_name:
class body
我们用关键字“class”在类名和分号后面定义一个类。在使用缩进之后,我们会考虑有缩进的所有东西。为了让这更容易理解,让我们看一个例子。
以汽车展厅为例。你要存储每辆车的详细信息。让我们首先定义一个类
class Car:
pass
就这样!
注意:我用pass语句代替了它的主体,因为主要目的是展示如何定义一个类,而不是它应该包含什么。
在详细介绍之前,首先要了解对象和实例化。
2.对象和对象实例化
当我们定义一个类时,只会创建对象的描述或蓝图,在这个过程中没有内存分配。而对象实例具有内存分配,它包含真实的数据或信息。
实例化是创建一个类的实例。让我们创建上面定义的类的对象-
obj1 = Car()
这样就创建了一个对象实例。请注意,你可以根据你的选择更改对象名称。
尝试打印此对象
print(obj1)
因为我们的类是空的,所以它返回存储对象的地址,即0x7fc5e677b6d8
在继续学习之前,你还需要了解类的构造函数。
类构造函数
到目前为止,我们有一辆空的车,是时候把车的特征填满我们的类了。类构造函数的工作是在创建类的对象时将值分配给类的数据成员。
一辆车可以有不同的属性,如名称、颜色、型号、品牌、发动机功率、重量、价格等。我们将仅选择其中几项以便于理解。
class Car:
def __init__(self, name, color):
self.name = name
self.color = color
因此,car或任何其他对象的属性必须位于一个我们称为 __init__( )的方法中。此方法也称为构造函数方法。每当类的对象被构造时,就调用构造函数方法。
现在,让我们来讨论一下 __init__( )方法的参数。所以,这个方法的第一个参数必须是self。然后才是剩下的参数
构造函数方法中的两个语句是
- self.name = name
- self.color = color:
这将创建新的属性,即name和color,然后将参数的值分配给它们。“self”关键字表示类的实例。通过使用“self”关键字,我们可以访问类的属性和方法。它在方法定义和变量初始化中很有用。“self”在每次定义方法时都显式使用。
注意:你也可以在此方法之外创建属性。但是这些属性对整个类都是通用的,必须给它们赋值。
假设你的展厅中的所有汽车都是Sedan,而不是一次又一次地指定它,你可以通过创建一个属性来将car_type的值固定为Sedan。
class Car:
car_type = "Sedan" #类属性
def __init__(self, name, color):
self.name = name #实例属性
self.color = color #实例属性
这里,实例属性是指构造函数方法中的属性,在这个例子中是self.name 和 self.color。类属性是指构造函数方法之外的属性,在这个例子中是car_type。
3.类方法
到目前为止,我们已经添加了汽车的属性。现在是时候添加一些行为了。方法是我们用来描述对象行为的函数。它们也在类中定义。请看下面的代码
class Car:
car_type = "Sedan"
def __init__(self, name, mileage):
self.name = name
self.mileage = mileage
def description(self):
return f"The {self.name} car gives the mileage of {self.mileage}km/l"
def max_speed(self, speed):
return f"The {self.name} runs at the maximum speed of {speed}km/hr"
在类中定义的方法(而不是构造函数方法)称为实例方法。此外,这里有两个实例方法,description()和max_speed()。
- description()—此方法返回一个字符串,其中包含汽车的描述,如名称和里程数。此方法没有其他参数。此方法正在使用实例属性。
- max_speed()—此方法有一个附加参数,并返回一个显示车辆名称及其速度的字符串。
请注意,附加参数speed没有使用“self”关键字。因为speed不是一个实例变量,所以我们不使用self关键字作为前缀。让我们为上面描述的类创建一个对象。
obj2 = Car("Honda City",24.1)
print(obj2.description())
print(obj2.max_speed(150))
我们所做的是创建一个类car的对象并传递所需的参数。为了使用object_name.method_name().
description()方法没有任何附加参数,因此在调用它时没有传递任何参数。
max_speed()方法有一个附加参数,因此我们在调用它时传递了一个参数。
注意:三件重要的事要记住
-
可以创建一个类的任意数量的对象。
-
如果方法需要n个参数,而你没有传递相同数量的参数,则会发生错误。
-
参数的顺序很重要。
让我们一个个来看看
- 创建一个类的多个对象
class Car:
def __init__(self, name, mileage):
self.name = name
self.mileage = mileage
def max_speed(self, speed):
return f"The {self.name} runs at the maximum speed of {speed}km/hr"
Honda = Car("Honda City",21.4)
print(Honda.max_speed(150))
Skoda = Car("Skoda Octavia",13)
print(Skoda.max_speed(210))
- 参数数目错误
class Car:
def __init__(self, name, mileage):
self.name = name
self.mileage = mileage
Honda = Car("Honda City")
print(Honda)
因为我们没有提供第二个参数,所以我们得到了这个错误。
- 参数顺序
class Car:
def __init__(self, name, mileage):
self.name = name
self.mileage = mileage
def description(self):
return f"The {self.name} car gives the mileage of {self.mileage}km/l"
Honda = Car(24.1,"Honda City")
print(Honda.description())
搞混了!因为我们改变了论点的顺序。
现在,面向对象编程有四个基本概念:继承、封装、多态和数据抽象。为了理解OOPs,了解所有这些非常重要。到目前为止,我们已经介绍了面向对象编程的基本知识,让我们进一步深入。
4. Python类中的继承
继承是一个类继承另一个类的属性和方法的过程。被继承的类称为父类。从父类继承属性的类是子类。
有趣的是,除了继承的属性和方法外,子类可以有自己的属性和方法。
如何继承父类?使用以下语法:
class parent_class:
body of parent class
class child_class( parent_class):
body of child class
让我们看看实现
class Car: #父类
def __init__(self, name, mileage):
self.name = name
self.mileage = mileage
def description(self):
return f"The {self.name} car gives the mileage of {self.mileage}km/l"
class BMW(Car): #子类
pass
class Audi(Car): #子类
def audi_desc(self):
return "This is the description method of class Audi."
obj1 = BMW("BMW 7-series",39.53)
print(obj1.description())
obj2 = Audi("Audi A8 L",14)
print(obj2.description())
print(obj2.audi_desc())
我们创建了两个子类,即“BMW”和“Audi”,它们继承了父类“Car”的方法和属性。在BMW类我们没有提供额外的特征和函数。而Audi内部的一个附加方法。
注意在obj1.description()和obj2.description()的帮助下,父类的实例方法description()是如何被子类的对象访问的。此外,还可以使用obj2.Audi_desc()访问Audi类的单独方法。
5.封装
正如我在文章开头部分提到的,封装是确保安全性的一种方法。基本上,它将数据隐藏起来,不让外人访问。例如,如果我们想让某些值不被客户或任何未经授权的人访问,那么封装就是确保这一点的方法。
你可以在方法或属性的名称前使用一个下划线( _ ) 来声明受保护的方法或属性。例如 self._name或def _method();这两行都说明属性和方法是受保护的,不应在类和子类的访问之外使用,而是可以由类方法和对象访问。
Python只是将‘_‘ 用作编码约定,告诉你应该在类的范围内使用这些属性/方法。你仍然可以像往常一样访问定义为受保护的变量和方法。
现在,为了实际防止从类范围之外访问属性/方法,可以使用“私有成员”。若要将属性/方法声明为私有成员,请在前缀中使用双下划线( __ ) 。例如– self.__name或def __method();这两行都说明属性和方法是私有的,不能从类外部进行访问。
class car:
def __init__(self, name, mileage):
self._name = name #受保护属性
self.mileage = mileage
def description(self):
return f"The {self._name} car gives the mileage of {self.mileage}km/l"
obj = car("BMW 7-series",39.53)
#通过类方法访问受保护变量
print(obj.description())
#直接从外部访问受保护变量
print(obj._name)
print(obj.mileage)
请注意我们如何访问受保护的变量而没有任何错误。很明显,对变量的访问仍然是公开的。让我们看看封装是如何工作的
class Car:
def __init__(self, name, mileage):
self.__name = name #私有变量
self.mileage = mileage
def description(self):
return f"The {self.__name} car gives the mileage of {self.mileage}km/l"
obj = Car("BMW 7-series",39.53)
#通过类方法访问私有变量
print(obj.description())
#直接从外部访问私有变量
print(obj.mileage)
print(obj.__name)
当我们尝试使用description()方法访问私有变量时,没有遇到任何错误。但是当我们尝试直接在类外部访问私有变量时,Python给出了一个错误,声明:car对象没有属性''__name'。
你仍然可以使用该属性的修饰名称直接访问它。Name mangling(命名修饰)是一种从外部访问类成员的机制。Python解释器将任何带有“__var”的标识符重写为“_ClassName__var”。使用这个你可以从外部访问类成员。
class Car:
def __init__(self, name, mileage):
self.__name = name #私有变量
self.mileage = mileage
def description(self):
return f"The {self.__name} car gives the mileage of {self.mileage}km/l"
obj = Car("BMW 7-series",39.53)
#通过类方法访问私有变量
print(obj.description())
#直接从外部访问私有变量
print(obj.mileage)
print(obj._car__name) #名称修饰
请注意,这个规则的设计是想处理某些情况,例如在调试器中。但是正常编程中不推荐使用
6.多态
多态(Polymorphism)一个希腊单词。如果我们分解Polymorphism这一术语,我们会得到“poly”(多)和“morph”(变形)形式。所以多态性意味着有多种形式。在OOP中,它指的是具有相同名称但具有不同功能的函数。
class Audi:
def description(self):
print("This the description function of class AUDI.")
class BMW:
def description(self):
print("This the description function of class BMW.")
audi = Audi()
bmw = BMW()
for car in (audi,bmw):
car.description()
使用对象audi调用函数时,将调用audi类的函数;使用对象bmw调用函数时,将调用bmw类的函数。
7.数据抽象
我们使用抽象来隐藏函数的内部细节或实现,只显示其功能。这与你在不知道汽车原理的情况下知道如何驾驶汽车,或者你知道如何用开关打开或关闭灯,但你不知道插座后面发生了什么的情况类似。
任何具有至少一个抽象函数的类都是抽象类。为了首先创建一个抽象类,你需要从ABC模块导入ABC类。这使你可以在其中创建抽象方法。ABC代表抽象基类。
from abc import ABC
class abs_class(ABC):
Body of the class
重要的是,不能为抽象类创建实例对象。例如-
from abc import ABC, abstractmethod
class Car(ABC):
def __init__(self,name):
self.name = name
@abstractmethod
def price(self,x):
pass
obj = Car("Honda City")
现在的问题是我们如何准确地使用这个抽象。答案是使用继承。
from abc import ABC, abstractmethod
class Car(ABC):
def __init__(self,name):
self.name = name
def description(self):
print("This the description function of class car.")
@abstractmethod
def price(self,x):
pass
class new(Car):
def price(self,x):
print(f"The {self.name}'s price is {x} lakhs.")
obj = new("Honda City")
obj.description()
obj.price(25)
Car是从ABC模块的ABC类继承的抽象类。注意我在抽象类中有一个抽象方法(price())和一个具体方法(description())。这是因为抽象类可以同时包含这两种类型的函数,而普通类则不能。从这个抽象类继承的另一个类是new。new的price()方法是我们重写了抽象类Car的price方法。
在用户从new()类创建对象并调用price()方法之后,new()类中price方法的定义就开始发挥作用了。这些定义对用户是隐藏的。抽象方法只是提供一个声明。需要提供子类的定义。
但是,当为new()类(即obj)的对象调用description()方法时,将调用Car的description()方法,因为它不是抽象方法。
结尾
总之,在本文中,我介绍了Python中面向对象编程的基本概念。现在你们知道OOPs和基本概念了。
原文链接:https://www.analyticsvidhya.com/blog/2020/09/object-oriented-programming/
欢迎关注磐创AI博客站:
http://panchuang.net/
sklearn机器学习中文官方文档:
http://sklearn123.com/
欢迎关注磐创博客资源汇总站:
http://docs.panchuang.net/
网友评论