目录

类是实例的抽象, 实例是类的具体化.

Python 中的类分为 经典类新式类. 前者现在已经很少用到了, 其特点就是可以不需要继承任何父类;后者则刚好相反, 形式类必须至少有一个父类, 如果没有特定的父类需要继承时, 至少需要继承基类 object, 在后面给出例子.

最简单的类

一个最简单的类可以不具有任何的函数, 仅仅是用作生成一个命名的空间.

In [1]: class MyData(object):
...: pass
...: In [2]: mydata = MyData() In [3]: mydata.x = 1 In [4]: mydata.y = 2 In [5]: mydata.x + mydata.y
Out[5]: 3

这样的类作为容器对象来共享命名空间, 类 MyData 的实例 mydata 将 mydata.x 和 mydata.y 关联到同一个命名空间中, 所以也只能通过实例名称结合句点标识符 ‘.’ 来调用, 这就是所谓的使用类作为命名空间容器. 需要注意的是, x 和 y 并不是类的属性而是实例的属性.

类方法

类方法定义在类的代码块中, 只能被类的实例调用, 所以在定义了一个类方法之后, 如果想调用它需要通过下面几个步骤:

1. 创建一个实例对象

2. 用实例对象结合句点标识符调用此类方法

class MyData(object):
def print_foo(self):
print "You invoked print_foo()!" if __name__ == '__main__':
mydata = MyData()
mydata.print_foo()

上面的函数声明中有一个 self 形参, 这是所有类函数都必须带有的形参, 表示类的实例对象. 类似与 Java 的 this 关键字. 在实例化对象后(生成类实例的过程), 使用类的实例对象调用类函数时, Python 解析器会自动的将类实例对象的引用传递给 self 形参, 所以我们不需要显示的传递该形参的实参. 所以当我使用类 MyData 的实例对象 mydata 调用类函数 print_foo() 时, 并没由传入任何的实参.

那么为什么需要传递类的实例对象给 self 形参呢?

就像之前提到的, 类函数只能通过类实例来调用, 实际上在类定义中我们会频繁的使用到 self 关键字, 这是为了保证类定义内的属性和函数都是被类的实例化对象所调用的, 而且可以实现创建多个不同的类对象。支撑了封装(保证数据的隔离是安全)的实现. self 关键字还有许多需要注意的地方, 这个我们以后再聊.

构造器 __init__()

类函数 __init__() 是 Python 类中预定义的方法,需要被重载才会生效。以双下划线 “__” 开头和结尾, 在 Python 中使用这种命名方式的方法会被理解为是一种特殊方法, Python 的特殊方法功能非常丰富, 种类也很多, 在声明变量名的时候要注意不要和特殊方法重名.

通常,构造器用于在 实例化对象被创建后,返回这个实例之前 的这段时间里,执行一些特定的任务或设置。例如:初始化实例对象属性(以 self 关键字调用的属性)。它在实例化一个新的对象时被自动调用,所以除了初始化实例属性之外,还常被用于运行一些初步的诊断代码。其调用的具体步骤:

1. 创建类的实例化对象

2. Python 解析器检查类是否实现了构造器

3. 若有,则执行构造器的实现,且要求创建对象的时候传入对应的实参。实例对象会传递给第一个形参 self 。

4. 若没有,则直接返回实例对象

一般建议在构造器中设定需要初始化的实例属性

创建一个类

class AddBrookEntry(object):
"""Address book entry class.""" def __init__(self, name, phone):
self.name = name
self.phone = phone
print "Create instance for:", self.name def updatePhone(self, new_phone):
self.phone = new_phone
print "Update the phone# for:", self.phone

实例化一个对象

In [3]: jmilkfan = AddrBookEntry('fanguiju', '123-123-123')
Create instance for: fanguiju

NOTE: 在实例化有一个类对象时,需要传递类构造函数中的所有形参,否则会出现 TypeError,所以说构造器的作用之一就是初始化类实例对象所需要的实例属性。

调用实例的方法和属性

通过实例化所得到的对象,拥有在类定义中所有使用 self 关键字来调用的属性和方法。这些被称之为实例化对象的属性和方法。

In [4]: jmilkfan.name
Out[4]: 'fanguiju' In [5]: jmilkfan.phone
Out[5]: '123-123-123' In [6]: jmilkfan.updatePhone("456-456-455")
Update the phone# for: 456-456-455 In [7]: jmilkfan.phone
Out[7]: '456-456-455'

创建子类

子类的创建通过集成父类的方法来实现,子类拥有父类所有公开的属性和方法。并且在子类中还可以对这些继承而来的方法和属性进行重载(在不改变属性和方法名的前提之下,修改属性值或方法的内部实现),而不会影响到父类的定义。所以子类除了集成父类的属性和方法之外,还可以修改继承所得到的属性和方法,也可以定义新的属性和方法。这样的话就大大增加了代码的重用。

NOTE:子类应该拥有自己的构造器,若有,则在实例化子类对象时,除了要传入子类对象所需要初始化的实参之外,还应传入实例化父类对象所需要的实参,且需要在子类构造器中显式的调用父类构造器来完成传递这些实参;若没有,则默认使用父类的构造器。

class EmpAddressBookEntry(AddrBookEntry):
"Employee address book entry class" def __init__(self, name, phone, id, email):
AddrBookEntry.__init__(name, phone)
self.id = id
self.email = email
print "Create instance for:", self.name def updateEmail(self, new_email):
self.email = email
print "Update the Email# for:", self.email

因为子类重载了父类的构造器,所以必须显式(className.__init__())的写出父类构造器才会被调用。

而且需要注意的是:我们还需要显式的将 self 传递给父类构造器,在子类中的 self 表示子类的实例化对象。所以如果希望子类的实例化对象能够调用父类的属性和方法的话就需要将表示子类实例化对象的 self 传递给父类,来替换父类的实例化对象,从而实现了将子类的实例化对象绑定到父类。这样才真正的实现了继承。

NOTE

1. 在子类的声明语句中继承了父类 AddrBookEntry

2. 在子类的构造器中调用了父类的构造器

3. 在子类中定义了新的子类属性和方法

使用 super() 来调用父类的构造器

一般来说我们很少使用 AddrBookEntry.__init__(name, phone) 这种方式来调用父类的构造器,因为 Python 支持多继承,所以我们希望可以有方法让子类自动的找到父类,这个方法就是 super() .

In [33]: class EmpAddressBookEntry(AddrBookEntry):
...: "Employee address book entry class"
...:
...: def __init__(self, name, phone, id, email):
...: super(EmpAddressBookEntry, self).__init__(name, phone)
...: self.id = id
...: self.email = email
...: print "Create instance for:", self.name
...:
...: def updateEmail(self, new_email):
...: self.email = new_email
...: print "Update the Email# for:", self.email

super(EmpAddressBookEntry, self) 语句返回了类 EmpAddressBookEntry 的父类,并且通过句点标识符来调用且传递了实参数给父类的构造器。

实例化子类对象

In [16]: jmilk_fan = EmpAddressBookEntry('fanguiju', '123-123-123-123', 1, 'fanguiju@gmail.com')
Create instance for: fanguiju
Create instance for: fanguiju

实例化子类对象时,需要一同传递实例化父类对象的实参(name, phone)。

调用子类的属性和方法

Out[17]: 'fanguiju'

In [18]: jmilk_fan.phone
Out[18]: '123-123-123-123' In [19]: jmilk_fan.id
Out[19]: 1 In [20]: jmilk_fan.email
Out[20]: 'fanguiju@gmail.com' In [22]: jmilk_fan.updatePhone("456-456-456")
Update the phone# for: 456-456-456 In [23]: jmilk_fan.phone
Out[23]: '456-456-456' In [29]: jmilk_fan.email
Out[29]: 'fanguiju@163.com'

因为子类 EmpAddressBookEntry 继承了父类 AddrBookEntry 所以子类也就拥有了父类的属性和方法,可以通过子类对象或直接在子类定义中调用。

类/属性/方法的命名规则

  • class: 大写字母开头的驼峰规则,EG class MyClass()

  • def: 小写字母开头的下划线驼峰规则,EG def set_my_function()。方法名应当指出对对象执行的操作,为名称和动词的结合。

  • 属性: 全小写字母的下划线驼峰规则,EG my_name =。属性名一般使用名称,代表一个对象的称呼。

Python 进阶_OOP 面向对象编程_类和继承的更多相关文章

  1. Python 进阶_OOP 面向对象编程_组合与继承

    #目录 前言 组合 派生 通过继承来覆盖重载方法 最常用的重载场景实例方法的重载 从标准类中派生类方法的重载 前言 我们定义一个类是希望能够把类当成模块来使用,并把类嵌入到我们的应用代码中,与其他的数 ...

  2. Python 进阶_OOP 面向对象编程_类属性和方法

    目录 目录 类属性 调用类属性 查看类属性 特殊的类属性 类方法 真构造器 __new__ 类属性 在理解类属性之前要先搞清楚 实例属性 和 函数属性 之间的区别: 1. 实例属性:指的是实例化类对象 ...

  3. Python 进阶_OOP 面向对象编程_实例属性和方法

    目录 目录 构造器和解构器 构造器 __init__ 真构造器 __new__ 解构器 __del__ 实例方法 Python 中的 抽象方法 实例属性 查看实例属性 实例属性和类属性的区别 访问不可 ...

  4. Python 进阶_OOP 面向对象编程_静态方法和类方法

    目录 目录 静态方法 类方法 使用函数修饰符来声明静态方法和类方法 静态方法 静态方法仅是类中的函数, 不需要绑定实例, 也就是说静态方法的定义不需要传入 self 参数. 静态方法不属于类的某一个实 ...

  5. Python 进阶_OOP 面向对象编程_self 的实例绑定

    目录 目录 self 和绑定 调用非绑定的方法 self 和绑定 在 Python 中 self 变量是特殊的, 其用于在实例方法中引用该方法所绑定的实例, 换句话说就是 Python 在实例化对象时 ...

  6. C++ Primer 学习笔记_72_面向对象编程 --句柄类与继承[续]

    面向对象编程 --句柄类与继承[续] 三.句柄的使用 使用Sales_item对象能够更easy地编写书店应用程序.代码将不必管理Item_base对象的指针,但仍然能够获得通过Sales_item对 ...

  7. Python进阶之面向对象编程

    面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程序设计把计算机 ...

  8. Python进阶之面向对象编程(二)

    Python面向对象编程(二) .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans GB& ...

  9. Python进阶之面向对象编程概述

    Python面向对象编程(一) .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans GB& ...

随机推荐

  1. Spring Security 01

    环境搭建 maven依赖jar包 <!-- spring-security --> <dependency> <groupId>org.springframewor ...

  2. tp增删改查

    增: 向数据库增加新的数据,这里增是纯粹的增添数据,如果新增的数据包含主键,并且该主键已经在数据库存在,则无法新增数据的. //M("User") 用于高效实例化一个数据模型(M ...

  3. 这样设计 Java 异常更优雅,赶紧学!

    来源:lrwinx.github.io/2016/04/28/如何优雅的设计java异常/ 导语 异常处理是程序开发中必不可少操作之一,但如何正确优雅的对异常进行处理确是一门学问,笔者根据自己的开发经 ...

  4. CF1105C Ayoub and Lost Array ——动态规划

    CF1105C Ayoub and Lost Array 题意:一个整数数组,满足: 1. 长度为n 2. 所有元素都在[l, r]范围内 3. 所有元素的和能被3整除给出n, l, r (1 ≤ n ...

  5. [NOIP2016PJ]魔法阵

    今天模拟赛的题,,,唯一没有Giao出来的题(不然我就AKIOI了~) 最开始没想到数学题,把所有部分分都说一遍吧: 35分:纯暴力O(M^4)枚举,对于每一组a,b,c,d验证其是否合法. 60分: ...

  6. P4195 【模板】exBSGS/Spoj3105 Mod

    传送门 首先要懂得 $BSGS$,$BSGS$ 可以求出关于 $Y$ 的方程 $X^Y \equiv Z (mod\ mo)$ 的最小解,其中 $gcd(X,Z)=1$ $exBSGS$ 算是 $BS ...

  7. php开启xdebug扩展及xdebug通信原理

    xdebug调试原理 IDE(如PHPStorm)已经集成了一个遵循BGDP的XDebug插件,当开启它的时候, 会在本地开一个XDebug调试服务,监听在调试器中所设置的端口上,默认是9000,这个 ...

  8. Redis这篇就够了

    Redis 简介 Redis 优势 Redis 数据类型 string hash list set Zset 小总结 基本命令 发布订阅 简介 实例 发布订阅常用命令 事务 实例 Redis 事务命令 ...

  9. 使用logstash同步MongoDB数据到es

    input{ mongodb{ codec => "json" uri => 'mongodb://127.0.0.1:27017/kuaibao' placehold ...

  10. Django 项目环境搭建

    环境 mkvirtualenv -p python3.6 mytest # 创建虚拟环境 workon mytest # 进入虚拟环境 # 按照基础环境依赖 pip install django==1 ...