其实已经有中文版了,只是为了加深理解,遂翻译出来。
Ex40:模块(modules),类(classes),对象(Objects)
译文:
Python可以被称之为“面向对象的编程语言”。这就意味着Python中有种叫做“类”的结构,可以将你的软件用特定方式结构化。使用类可以增加程序之间的相容性,这样可以让程序更加简洁,至少理论上是这样的。
接下来我会用你现在已经了解的字典(dictionary)和模块,来教你面向对象编程、类,以及对象的基础知识。我的麻烦在于面向对象编程(OOP)非常不可思议。你要做的就是尽力去做,尝试着去理解我所说的,敲代码,然后在下一个练习中我会再次重复阐述。
开始吧。
模块类似于字典
你已经知道如何生成和使用字典,它就是把一个东西映射到另一个东西的方法。也就是说如果你的字典中有一个关键字(key)“apple”,想要获取它就需要用如下语句:
mystuff = {'apple': "I AM APPLES!"}
print mystuff['apple']
记住“从Y获取X”的这种思想,现在来想想模块。这段时间你已经创建了许多模块,并且用过,你了解到它们是:
- 一个Python文件,其中包含了一些函数或变量
- 然后你需要导入该文件
- 这样做之后,你就可以使用“.”(dot)操作符,来获取这个模块中的函数或变量
试想,如果我有一个命名为mystuff.py的模块,并且在其中有一个名叫apple的函数。以下为mystuff.py模块:
# this goes in mystuff.py
def apple():
print "I AM APPLES!"
一旦我有了它,就可以用import使用这个模块,然后获取apple函数:
import mystuff
mystuff.apple()
我还可以在其中创建一个叫做tangerine的变量:
def apple():
print "I AM APPLES!"
# this is just a variable
tangerine = "Living reflection of a dream"
还是可以用相同的方式访问:
import mystuff
mystuff.apple()
print mystuff.tangerine
回想字典,你应该发现这和使用字典是多么相似,但是语法不同,让我们来做个对比:
mystuff['apple'] # get apple from dict
mystuff.apple() # get apple from the module
mystuff.tangerine # same thing, it's just a variable
也就是说Python中有一个很常见的模式:
- 使用一个关键字=值(key=value)风格的容器
- 通过关键字的名字从中获取东西。
对于字典来说,关键字是一个字符串(string),语法是[key]。对于模块来说,关键字是一个标识符(identifier),语法为.key。除此之外,它们差不多是同一个东西。
类类似于模块
一种理解模块的方式是,它们是可以存储Python代码的特殊字典,因此你可以用’.’操作符来访问它的内容。Python还有另一种满足相似要求的结构,叫做类(class)。类是把一组函数和数据放置在一个容器中的方法,这样你可以通过’.’操作符访问它们(这些函数和数据)。
如果我要创建一个类似于mystuff模块的类,我会如下做:
class MyStuff(object):
def __init__(self):
self.tangerine = "And now a thousand years between"
def apple(self):
print "I AM CLASSY APPLES!"
这看起来比模块要复杂,通过对比,它肯定进行了更多操作,但是你要能弄清楚为什么它像一个“mini-module”,并且这个“迷你模块”MyStuff中有apple()函数。可能比较让人困惑的是__init__()函数和用self.tangerine来设置tangerine变量的用法。
使用类而不是模块的原因如下:你可以使用上面的类,并且用它生成很多相同的类,如果你想的话可以一次性生成上百万个,并且它们之间不会相互干扰。而使用模块时,你一次只能引入一个给整个程序,除非你做一些非人的尝试。
在可以理解这些之前,你需要知道对象(object)是什么,以及怎么使用MyStuff,就像你对mystuff.py模块所做的。
对象类似于mini导入(import)
如果说类像一个“迷你模块”,那么这里一定还有一个和import相似的概念用于类。这个概念叫做“实例化(instantiate)”,也就是“create(创建)”的一种高级说法。当你实例化一个类,你所获得的东西就被称之为对象。
实例化的方法就是像调用函数一样调用一个类,如下:
thing = Mystuff()
thing.apple()
print thing.tangerine
第一行就是“实例化”操作,它很像调用一个函数。然而,当你调用它时,Python配合你做了一系列的事,我将详细描述上面使用MyStuff的代码段的过程:
- Python 查找MyStuff(),确定它是你定义的一个类
- Python生成一个空的对象,该对象包含所有你在类中用def定义的函数
- 然后Python会确定你是否创建了一个“神奇的”__init__函数,当你调用它时,这个函数会将新创建的空对象初始化
- 在MyStuff的__init__函数中,会得到一个额外的变量self,它是这个空对象为你创造的,你可以利用模块、字典或者其他对象,将变量的值赋给它
- 这种情况下,我将一首歌的歌词赋值给self.tangerine,这样我就已经初始化了这个变量
- 现在Python就可以使用这个新创建的对象,并将它赋值给thing变量之后供我使用
这就是Python在调用类时像调用函数一样先进行“迷你导入”的基本原理。记住,这个过程不是把类给你,而是使用这个类作为模板,告诉你怎样创建一个这类东西的副本。
你要记住我给你的是有点不准确的描述,这是为了让你在模块的知识基础上,对类的工作有初步认知。其实,从现在开始,类和对象就和模块区分开了。更直白一点说,我会作如下表述:
- 类就像是创建新的迷你模块的方案,或者说定义
- 实例化的本质是创建并导入这些迷你模块
- 被创建的迷你模块叫做一个对象,你能将它赋值给一个变量以供使用
在此表述之后,尽管类和对象与模块有很大的区别,但是这只能作为你理解类的一种方式。
从物获取物
现在有三种方式用于“从物获取物”:
# dict style
mystuff['apple']
# module style
mystuff.apple()
print mystuff.tangerine
# class style
thing = MyStuff()
thing.apples()
print thing.tangerine
第一个类的例子
你应该开始发现这三个 关键字=值 容器类型的相似之处,并且有一堆疑问了。记住这些问题,因为下一节练习中将会再三强调你的“面向对象词汇”。在这次练习中,我只需要你敲入这些代码,让它运行,这样在你继续学习之前能得到一些练习。
# -- coding: utf-8 --
class Song(object):
def __init__(self, lyrics):
self.lyrics = lyrics
# def __init__(self, lyrics)初始化新实例化的object,从Song()括号中的list,传值到lyrics中,
# 再赋值给self,后续的函数可以用self为传入参数
# self的使用:是用来区别lyrics是 实例的属性 或 局部变量,使用self.lyrics就能明确lyrics是实例的属性
def sing_me_a_song(self):
for line in self.lyrics:
print line
tem = ["Happy birthday to you",
"I don't want to get sued",
"So I'll stop right there"]
happy_bday = Song(tem)
# happy_bday = Song(["Happy birthday to you",
# "I don't want to get sued",
# "So I'll stop right there"])
bulls_on_parade = Song(["They rally around the family",
"With pockets full of shells"])
# 上面有两次实例化Song的原因,是要证明不论实例化多少次,不同的object之间不会互相影响
happy_bday.sing_me_a_song()
bulls_on_parade.sing_me_a_song()