目录

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

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. 排序,其他的运用 os fork

    while True: str_num = input("Enter number:") flag = True dotCount = 0 if str_num[0] == '-' ...

  2. CNN之池化层tf.nn.max_pool | tf.nn.avg_pool | tf.reduce_mean | padding的规则解释

    摘要:池化层的主要目的是降维,通过滤波器映射区域内取最大值.平均值等操作. 均值池化:tf.nn.avg_pool(input,ksize,strides,padding) 最大池化:tf.nn.ma ...

  3. JSP基础--EL表达式

    EL(表达式语言) 1 EL概述 1.1 EL的作用 JSP2.0要把html和css分离.要把html和javascript分离.要把Java脚本替换成标签.标签的好处是非Java人员都可以使用. ...

  4. IDEA永久破解方法

    链接: https://pan.baidu.com/s/1a1pMOP6rMrh-wJdUFSCqAw 提取码: 46cx 复制这段内容后打开百度网盘手机App,操作更方便哦

  5. BZOJ 3331 (Tarjan缩点+树上差分)

    题面 传送门 分析 用Tarjan求出割点,对点-双连通分量(v-DCC)进行缩点,图会变成一棵树 注意v-DCC的缩点和e-DCC不同,因为一个割点可能属于多个v-DCC 设图中共有p个割点和t个v ...

  6. P1021 邮票面值设计(dfs+背包dp)

    P1021 邮票面值设计 题目传送门 题意: 给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤15N+K≤15)种邮票的情况下 (假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大 ...

  7. 2019-6-23-WPF-托盘显示

    title author date CreateTime categories WPF 托盘显示 lindexi 2019-06-23 11:52:36 +0800 2018-11-21 11:19: ...

  8. 一、简单的图片上传并预览功能input[file]

    一.简单的图片上传并预览功能input[file] <!DOCTYPE html> <html lang="en"> <head> <me ...

  9. myeclipse2014删除antlr-2.7.2.jar--解决struts和hibernate包冲突

    方式一: 要求眼疾手快,在workspace下的D:\myeclipse2014workspace\.metadata\.me_tcat7\webapps\工程名\WEB-INF\lib中将antlr ...

  10. vim常用快捷键及操作记录

    1. 安装 sudo apt-get install vim 或者 yum install -y vim-enhanced 2. 具体使用技巧如下 打开文件: 命令/操作 说明 vim + filen ...