面向对象编程(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. 并发编程之详解InheritableThreadLocal类原理

    [本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究.若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!] 在Java并发编 ...

  2. 阿里druid数据源属性配置表

    https://cloud.tencent.com/developer/article/1368903 DRUID 属性说明表 属性(Parameter) 默认值(Default) 描述(Descri ...

  3. JavaWeb网上图书商城完整项目--day02-3.regist页面输入框失去焦点进行校验

    当输入框输入数据之后,当输入框失去焦点的时候,我们需要对输入的数据进行校验 l  用户名校验: 用户名不能为空: 用户名长度必须在3 ~ 20之间: 用户名已被注册(需要异步访问服务器). l  登录 ...

  4. 【面试篇】寒冬求职之你必须要懂的Web安全

    https://segmentfault.com/a/1190000019158228 随着互联网的发展,各种Web应用变得越来越复杂,满足了用户的各种需求的同时,各种网络安全问题也接踵而至.作为前端 ...

  5. 在采用K8S之前您必须了解的5件事情

    作者简介 Christopher Tozzi,自2008年来以自由职业者的身份对Linux.虚拟化.容器.数据存储及其相关主题进行报道. 时至今日,Kubernetes已然成为风靡一时的容器编排调度工 ...

  6. akka-typed(8) - CQRS读写分离模式

    前面介绍了事件源(EventSource)和集群(cluster),现在到了讨论CQRS的时候了.CQRS即读写分离模式,由独立的写方程序和读方程序组成,具体原理在以前的博客里介绍过了.akka-ty ...

  7. 入门大数据---Redis集群分布式学习

    Redis是什么? 官方介绍: Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件. 它支持多种类型的数据结构,如 字符串(strings), 散列( ...

  8. Json序列化帮助类

    public static class Json { public static object ToJson(this string Json) { return Json == null ? nul ...

  9. 并发04--JAVA中的锁

    1.Lock接口 Lock与Synchronized实现效果一致,通过获得锁.释放锁等操作来控制多个线程访问共享资源,但是Synchronized将获取锁固话,必须先获得锁,再执行,因此两者对比来说, ...

  10. Python实用笔记 (13)函数式编程——返回函数

    函数作为返回值 我们来实现一个可变参数的求和.通常情况下,求和的函数是这样定义的: def calc_sum(*args): ax = 0 for n in args: ax = ax + n ret ...