面向对象编程(Object-oriented programming, OOP)是一种基于对象概念的编程范式,可包含属性(attribute)形式的数据以及方法(method)形式的代码。另一种对 OOP 的解释是构建来灵活的且可复用的模块或是库,就像 Numpy 和 Pandas。

Python 中的所有内容都是对象。就像字符串(string)和列表(list)都是 Python 中的对象。而类就是创建对象的蓝图。基于面向对象机制编写的代码易于维护,是因为它的模块化结构,同时程序也因为封装而更安全。

这篇教程讨论了面向对象编程中的类、对象、方法、多态和继承,以给你提供一个良好的面向对象编程的基础。

点击免费领取:全网最全python学习导图+14张思维导图,让你学习不走弯路!

Python 现有的数据结构中就像整型还有字符串,都被设计为代表类似员工编号、员工姓名之类的东西。OOP 中的类就像是对象的蓝图,你还可以设计你自己的数据结构。举个例子,你可以创建一个 Employee 类来展现员工姓名和薪水的属性。

关键字calss 用以创建一个类,后面紧跟类型与冒号,类的主体部分起一新行并且缩进一个制表符。构造函数constructor是当你创建对象时被默认调用的一个方法,你需要通过关键字init来创建构造函数。在下面的例子当中,我创建了一个 Employee 类,与两个(class attributes)类属性 status 与 number_of_employee,同时两个(instance attributes)实例属性 employee_id 与 name,还有一个 give_info() 方法。

class Employee:

#class attributes
status = "active"
number_of_employee =

def __init__(self, employee_id, name):
self.employee_id = employee_id #instance attribute
self.name = name #instance attribute
Employee.number_of_employee +=

#class method
def give_info(self):
print("Name:",self.name,"\nID:",self.employee_id)

在表达式

self.employee_id = employee_id

中第一个 employee_id 是一个(instance attributes)实例属性或称为变量,第二个 employee_id 是一个参数,变量 name 也是同样的道理。当你通过类创建一个对象的时候,你可以这样写,

emre = Employee("", "Emre Kutlug")

对象

如前所述,类是创建对象的蓝图。一个类和对象的关系可以理解为动物和瑜伽熊的关系;瑜伽熊是一种动物,动物是一个抽象的概念,它以瑜伽熊和米老鼠的形式来实现。因此我们要先创建一个对象的类后才能使用它的方法和属性。

对象也被称为实例。因此,创建一个类的对象的过程也被成为实例化(instantiation)。在 Python 中创建类的对象,你必须在类名后紧跟圆括号。

我还可以使用type方法来检查这个对象的类型。输入:

type(emre)

输出:

<class '__main__.Employee'>

你可以通过类的对象来访问类的(class attributes)类属性和(instance attributes)实例属性或者调用类的方法。为此,你必须写下对象名后跟点(.)操作符与你想访问的属性名或是方法名,看看下面的例子吧,输入:

>>> emre.status
'active'
>>> emre.number_of_employee >>> emre.employee_id
''
>>> emre.give_info()
Name: Bob
ID:

属性

你可以用内建函数dir()来查看一个对象的所有属性和方法。Python 中有很多的内建的属性与方法,下面的例子将会展示 emre 对象中的所有属性与方法,其中前面带有双下划线的都是内嵌的。

>>> dir(emre)
['__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__', 'employee_id', 'give_info', 'name', 'number_of_employee', 'status']
>>>

两种类型的属性当中,(class attributes)类属性的值将贯穿全部的对象,而(instance attributes)实例属性的值会因对象的不同而不同。实例属性可以定义在任何方法当中,而类属性定义在方法之外。实例属性通过self关键字来引用,而类属性在方法中通过类名来引用。在下面的例子当中,我们先来看 number_of_employee 属性的值,再来创建一个同类的其他对象

>>> emre.number_of_employee

>>> emma = Employee("", "Emma Stone")
>>> emma.give_info()
Name: Emma Stone
ID:
>>>

当我们再在下面的例子当中输出 number_of_employee 的值的时候,将会是 2,因为这是类属性,两个对象都共享其值。

>>> emma.number_of_employee

>>> 

方法

前面提到过了,你可以用方法来实现对象的功能。之前我都是用一个类的对象来调用它的方法,但是还有另一种方法 —— 静态方法(static method),可以直接同过类名来调用。静态方法只能访问类属性,下面的例子当中,我将为 employee 类添加一个静态方法

class Employee:

#class attributes
status = "active"
number_of_employee =

def __init__(self, employee_id, name):
self.employee_id = employee_id #instance attribute
self.name = name #instance attribute
Employee.number_of_employee +=

#class method
def give_info(self):
print("Name:",self.name,"\nID:",self.employee_id)

@staticmethod
def get_class_objective():
message = "The objective of this Employee class is to organize employee information with more modular manner"
print (message)

输入:

>>> Employee.get_class_objective()
The objective of this Employee class is to organize employee information with more modular manner
>>>

全局变量与局部变量

类的属性也被称为是变量,变量又分为两种类型:局部变量和全局变量。类中的局部变量是在方法中定义的并只能再方法中访问到,因此你不能在 get_class_objective() 方法之外访问到 message 变量。当你试图访问的时候,将会得到 AttributError,

全局变量不被定义在任何方法当中,因此你可以在类种的任何地方访问到它们。之前例子当中的 status 与 number_of_employee 都是全局变量。

点击免费领取:全网最全python学习导图+14张思维导图,让你学习不走弯路!

封装

OOP 中有三个主要的概念:分装 Encapsulation、继承 Inheritance 与多态 Polymorphism。封装指的就是数据隐藏。OOP 中的一个类不应该直接就能访问到另一个类的数据,或者说数据的访问应该交由方法来控制着。你可以用私有变量和 property 来控制类数据的访问。在变量名前加上两个下划线便可定义私有变量,例如 __age 就是私有变量。

你可以为 age 属性创建一个 property 来符合这个逻辑,就像下面的代码一样。一个 property 有三个部分,你必须定义这个属性 —— 下例中为 age;接着你必须通过@property装饰器(decorator)来为属性定义 property;最后你必须创建一个 property setter,下例当中为 @age.setter 装饰器。你可以设定员工的年龄都必须在 19 到 99 岁之间,如果有人想给 age 属性设定超过其范围的值,将会引发报错并无法创建。

class Employee:

#class attributes
status = "active"
number_of_employee =

def __init__(self, employee_id, name, age):
self.employee_id = employee_id #instance attribute
self.name = name #instance attribute
self.age = age #instance attribute
Employee.number_of_employee +=

# Creates model property
@property
def age(self):
return self.__age

# Create property setter
@age.setter
def age(self, age):
if age < :
raise Exception('An Employee\'s age cannot be lower than 18')
elif age > :
raise Exception('An Employee\'s age cannot be upper than 99')
else:
self.__age = age

继承

OOP 中的继承就很像真实世界当中的孩子继承了他父母的一些特征,再加上自身独特的特征。继承了其他类的类被称为子类,被继承的类则为父类。就像下面这样

# Create Class Manager that inherits Employee
class Manager(Employee):

def set_team_size(self, team_size):
self.team_size = team_size

为了说明某类继承了一个类,你必须将其父类写在其类名后的圆括号之中。Manager 类可以访问到其父类 Employee 的全部属性与方法

>>> muge = Manager("", "Muge Ozkan", )
>>> muge.name
'Muge Ozkan'
>>> muge.status
'active'
>>> muge.get_class_objective()
The objective of this Employee class is to organize employee information with more modular manner
>>>

除了其父类的属性与方法之外,Manager 类还有他独有的 set_team_size() 方法,顺带一提,一个类可以有两个以上的父类或是子类。

多态

多态指的是一个对象可以有多种表现方式的能力,两种类型的多态分别是:方法重写和方法重载(method overriding and method overloading。)

方法重写

方法重写意味着在子类与父类当中有着同名方法,虽然其中的定义是不同的但他们都保留着相同的名字。如果你还记得我们在 Employee 类当中有一个 give_info() 的方法,我们便可以在 Manager 类当中进行重写,以显示经理类中的团大大小信息,

class Manager(Employee):

team_size =

def set_team_size(self, team_size):
self.team_size = team_size

def give_info(self):
print("Name:",self.name,"\nID:",self.employee_id,"\nTeam Size:",self.team_size)

接着

>>> muge = Manager("", "Muge Ozkan", )
>>> muge.give_info()
Name: Muge Ozkan
ID:
Team Size:
>>>

如你所见,当子类与父类都在调用同名方法时产生了不同的表现,是因为在子类中重写了父类的方法。

方法重载

你可以通过改变调用时参数的类型与个数来重载任何一个方法,这样这个方法将会有不同的表现。在下面的例子中,如果我们在调用 calculate_salary() 方法时只传一个参数,它将返回这个参数。然而如果我们传递两个参数,它将返回两数之和。

class Manager(Employee):

team_size =

def set_team_size(self, team_size):
self.team_size = team_size

def give_info(self):
print("Name:",self.name,"\nID:",self.employee_id,"\nTeam Size:",self.team_size)

def calculate_salary(self, salary, bonus=None):
if bonus is not None:
salary += bonus
return salary

接着

>>> muge = Manager("", "Muge Ozkan", )
>>> muge.calculate_salary() >>> muge.calculate_salary(, ) >>>

结论

本篇教程介绍了面向对象编程中的类、对象、属性和方法的概念,接着是封装、继承和多态,他们都是面向对象编程中的核心。OOP 是最常用的编程范例之一,因此大多数现代的编程语言像 Python 都支持面向对象编程。

想了解更多关于python的干货知识,请扫码下方二维码哦!

Python 中的面向对象编程的更多相关文章

  1. python中的面向对象编程

    在python中几乎可以完成C++里所有面向对象编程的元素. 继承:python支持多继承: class Derived(base1, base2, base3): pass 多态:python中的所 ...

  2. Python中的并发编程

    简介 我们将一个正在运行的程序称为进程.每个进程都有它自己的系统状态,包含内存状态.打开文件列表.追踪指令执行情况的程序指针以及一个保存局部变量的调用栈.通常情况下,一个进程依照一个单序列控制流顺序执 ...

  3. Python:笔记(3)——面向对象编程

    Python:笔记(3)——面向对象编程 类和面向对象编程 1.类的创建 说明:和Java不同的是,我们不需要显示的说明类的字段属性,并且可以在后面动态的添加. 2.构造函数 构造函数的功能毋庸置疑, ...

  4. Python学习之==>面向对象编程(二)

    一.类的特殊成员 我们在Python学习之==>面向对象编程(一)中已经介绍过了构造方法和析构方法,构造方法是在实例化时自动执行的方法,而析构方法是在实例被销毁的时候被执行,Python类成员中 ...

  5. Python 中的 TK编程

    可爱的 Python:Python 中的 TK编程 http://www.ibm.com/developerworks/cn/linux/sdk/python/charm-12/ python che ...

  6. 可爱的 Python : Python中的函数式编程,第三部分

    英文原文:Charming Python: Functional programming in Python, Part 3,翻译:开源中国 摘要:  作者David Mertz在其文章<可爱的 ...

  7. 22.python中的面向对象和类的基本语法

    当我发现要写python的面向对象的时候,我是踌躇满面,坐立不安呀.我一直在想:这个坑应该怎么爬?因为python中关于面向对象的内容很多,如果要讲透,最好是用面向对象的思想重新学一遍前面的内容.这个 ...

  8. Python中的多线程编程,线程安全与锁(二)

    在我的上篇博文Python中的多线程编程,线程安全与锁(一)中,我们熟悉了多线程编程与线程安全相关重要概念, Threading.Lock实现互斥锁的简单示例,两种死锁(迭代死锁和互相等待死锁)情况及 ...

  9. Python中的并行编程速度

    这里主要想记录下今天碰到的一个小知识点:Python中的并行编程速率如何? 我想把AutoTool做一个并行化改造,主要目的当然是想提高多任务的执行速度.第一反应就是想到用多线程执行不同模块任务,但是 ...

随机推荐

  1. 浅析pplx库的设计与实现。

    主要有三部分组成,threadpool,scheduler,task. 三者关系如上图示,pplx只着重实现了task部分功能,scheduler跟threadpool只是简略实现. threadpo ...

  2. WeChair项目Beta冲刺(7/10)

    团队项目进行情况 1.昨日进展    Beta冲刺第七天 昨日进展: 前后端并行开发,项目按照计划有条不絮进行 2.今日安排 前端:扫码占座功能和预约功能并行开发 后端:扫码占座后端逻辑开发,编码预约 ...

  3. Python 程序报错崩溃后,如何倒回到崩溃的位置?

    假设我们有一段程序,从 Redis 中读取数据,解析以后提取出里面的 name 字段: import json import redis client = redis.Redis() def read ...

  4. disruptor架构三 使用场景更加复杂的场景

    先c1和c2并行消费生产者产生的数据,然后c3再消费该数据 我们来使用代码实现:我们可以使用Disruptor实例来实现,也可以不用产生Disruptor实例,直接调用RingBuffer的api来实 ...

  5. Python表达式与生成式

    Python表达式与生成式 前言 本章节中的所有知识点均为在不丧失代码可读性的前提下最大程度精简代码的一系列操作.其中涉及到一些性能问题(微乎其微)可以不做考虑. 三元表达式 三元表达式中有三个重要的 ...

  6. Idea激活JRebel

    选择license激活 UUID 生成地址: http://www.uuid.online 激活地址 http://jrebel-license.jiweichengzhu.com/ UUID

  7. Selenium Grid的原理、配置与使用(转)

    Selenium GridSelenium Grid在前面介绍Selenium的时候说过它有三大组件,Selenium Grid就是其中之一而作用就是分布式执行测试.讲分布式之前还是要说说UI自动化的 ...

  8. web安全之跨站脚本漏洞(XSS)

    XSS(跨站脚本)概述以及pikachu上的实验操作 Cross-Site Scripting 简称为“CSS”,为避免与前端叠成样式表的缩写"CSS"冲突,故又称XSS. XSS ...

  9. $.post 参数定义

    //重置密码 function ResetPassword(id, accounts) { //alert("重置密码id-" + id + "-" + acc ...

  10. 117.填充每个节点的下一个右侧节点指针II

    # Definition for a Node.class Node: def __init__(self, val: int = 0, left: 'Node' = None, right: 'No ...