Learn Python the Hard Way 中文版

exercise41.学会说面向对象

在这个练习中,我要教你如何说“面向对象”,我要给你一些你需要知道定义的词。然后我会给你一组你必须了解的句子,最后我会给你一大堆练习,你必须完成这练习题,将我给你的句子转化成自己的词汇。

单词解释

class(类):告诉python去创建一个新类型。 object(对象):有两种意思,事物的基本类型,或者事物的实例化。 instance(实例):你通过python创建一个类所获得的。 def:用来在类中定义一个函数。 self:在一个类包含的函数中,self是一个用来访问实例或对象的变量。 inheritance:概念,表示一个类可以继承另一个类的特征,就像你和你的父母。 composition:概念,表示一个类可以包含其他类,就像汽车轮子。 attribute:类所拥有的特性,通常是变量。 is-a:惯用语,表示一个东西继承自另一个东西(a),像在“鲑鱼”是“鱼”。 has-a:惯用语,表示由其他事情或有一个特征(a),如“鲑鱼有嘴。”

花一些时间制作一些卡片用来记忆这些术语。像往常一样,直到你完成这个练习后,这都不会有太多的意义,但是首先你需要知道的基本词汇。

短语解释

接下来,在左边有一个Python代码片段列表,右面是他们的解释 class X(Y):创建一个叫X的类,并继承Y。 class X(object): def __init__(self, J):类X有一个__init__方法,该方法有self和J两个参数。 class X(object): def M(self, J):类X有一个叫M的函数,该函数有self和J两个参数。 foo = X():给foo赋值为类X的一个实例。 foo.M(J):从foo里调用M函数,传递的参数为self和J。 foo.K = Q:从foo里调用K属性,并将其设置为Q。

你可以把上面看到的所有的X, Y, M, J, K, Q, 以及 foo 看做空白的坑,比如,我还可以这么写:

  1. 创建一个叫??的类继承Y
  2. 类??有一个__init__方法,该方法有self和??两个参数。
  3. 类??有一个叫??的函数,该函数有self和??两个参数。
  4. 给foo赋值为类??的一个实例。
  5. 从foo里调用??函数,传递的参数为self和??。
  6. 从foo里调用??属性,并将其设置为??。

同样的,把这些写到卡片上,牢牢记住它们。卡片的前面写上python的小段代码,背面写上它们的解释,你要做到每当你看到正面的代码段的时候,能立即说出后面的解释。

组合练习

最后给你准备的是将单词和短语结合起来练习。我希望你能做到下面的要求:

  1. 准备好短语的卡片,并拼命的练习
  2. 翻转卡片,阅读这些解释语句,挑选出语句中包含单词练习中单词的卡片
  3. 通过这些语句拼命练习这些单词
  4. 坚持练习,直到你厌烦了,休息一下,然后继续练习

阅读测试

下面有一个python脚本,这个脚本会以无尽模式训练你,检验你所掌握的这些单词。这是一个很简单的脚本,它实现的功能是使用了一个叫做urllib的类库来下载我提供的单词列表。下面就是这个脚本,你需要正确的输入并命名为oop_test.py

import random
from urllib import urlopen
import sys

WORD_URL = "http://learncodethehardway.org/words.txt"
WORDS = []

PHRASES = {
    "class %%%(%%%):":
      "Make a class named %%% that is-a %%%.",
    "class %%%(object):\n\tdef __init__(self, ***)" :
      "class %%% has-a __init__ that takes self and *** parameters.",
    "class %%%(object):\n\tdef ***(self, @@@)":
      "class %%% has-a function named *** that takes self and @@@ parameters.",
    "*** = %%%()":
      "Set *** to an instance of class %%%.",
    "***.***(@@@)":
      "From *** get the *** function, and call it with parameters self, @@@.",
    "***.*** = '***'":
      "From *** get the *** attribute and set it to '***'."
}

# do they want to drill phrases first
if len(sys.argv) == 2 and sys.argv[1] == "english":
    PHRASE_FIRST = True
else:
    PHRASE_FIRST = False

# load up the words from the website
for word in urlopen(WORD_URL).readlines():
    WORDS.append(word.strip())


def convert(snippet, phrase):
    class_names = [w.capitalize() for w in
                   random.sample(WORDS, snippet.count("%%%"))]
    other_names = random.sample(WORDS, snippet.count("***"))
    results = []
    param_names = []

    for i in range(0, snippet.count("@@@")):
        param_count = random.randint(1,3)
        param_names.append(', '.join(random.sample(WORDS, param_count)))

    for sentence in snippet, phrase:
        result = sentence[:]

        # fake class names
        for word in class_names:
            result = result.replace("%%%", word, 1)

        # fake other names
        for word in other_names:
            result = result.replace("***", word, 1)

        # fake parameter lists
        for word in param_names:
            result = result.replace("@@@", word, 1)

        results.append(result)

    return results


# keep going until they hit CTRL-D
try:
    while True:
        snippets = PHRASES.keys()
        random.shuffle(snippets)

        for snippet in snippets:
            phrase = PHRASES[snippet]
            question, answer = convert(snippet, phrase)
            if PHRASE_FIRST:
                question, answer = answer, question

            print question

            raw_input("> ")
            print "ANSWER:  %s\n\n" % answer
except EOFError:
    print "\nBye"

运行这个脚本,尝试将这些“面向对象的短语”翻译成自己的语言。你应该能看到字典PHRASES中包含了刚才练习的所有的短语。

练习将英语转换为代码

接下来,你可以使用"english"选项来执行脚本,这样你可以反过来练习:

$ python oop_test.py english

记住这些短语使用的是无意义的词汇。学习阅读代码的一部分是停止纠结这些用于变量和类的名字的真实意义。人们常常会在读到一个像“cork”的词时突然迷糊,因为这个词会混淆他们的意义。在这个例子中,"Cork"只是用来作为一个类的名字。不要给它任何意义的解释。

阅读更多的代码

你现在需要继续阅读更多的代码,阅读你找到的代码中这些你刚学过的短语表达。你需要找出文件中所有的类,然后执行以下步骤:

  1. 给出每一个类的名字,并说出这些类继承哪些类
  2. 列出每个类所包含的函数,以及函数需要的参数
  3. 列出类所有的属性
  4. 对每个属性,给出属性的类型

这个练习的目的是通过阅读真实的代码,学习你刚才学到的短语是如何使用的。如果你练习的足够所,你应该能看到这些模式在代码中向你大声呼喊,然而在这之前,他们是你所不知道的,只是模糊的空白而已。

常见问题

Q: 这句代码result = sentence[:]实现了什么

这是python中用来复制列表的一种方式。你使用了列表的分割切片语法[:],得到列表从第一个到最后一个元素的切片。

Q: 这个脚本很难跑起来啊

你需要输入这些代码并保证它能运行。这个脚本可能会有一些小问题,但是它并不复杂。试着用你到目前为止学到的东西来调试脚本,每输入一行,确认一下是否与我的代码一样,并在网上搜索你所不了解的所有问题。

Q: 这对我来说太难了!

你可以的,慢慢来,如果需要的话,你逐个字符的输入,然后弄明白它是做什么的。