练习41
一些示意和概念
class X(Y)
: “Make a class named X that is-a Y.”
class X(object): def init(self, J)
类 X 有一个带有 self 和 J 参数的 init
函数。 (“class X has-a init
that takes self and J parameters.”)
class X(object): def M(self, J)
: 类 X 有一个带有 self 和 J 参数的 M 函数。 (“class X has-a function named M that takes self and J parameters.”)
**注意这边init和M是不一样的**
foo = X()
: 设 foo 为类 X 的一个实例。 (“Set foo to an instance of class X.”)
foo.M(J)
从 foo 那里获取 M 函数,并用 self 和 J 参数来调用它。 (“From foo, get the M function, and call it with parameters self, J.”)如果啥都没说,那就是只用self参数
foo.K = Q
从 foo 那里获取 K 属性,并设它为 Q。 (“From foo, get the K attribute, and set it to Q.”)
接下来是ex41.py的代码,首先需要import三个库,random,urlopen,sys,给word链接,给words的一个list,然后把需要的屏蔽后的短句当成一个phrases输进去。
在此省略打字部分
import random
from urllib.request import urlopen
import sys
WORD_URL = "http://learncodethehardway.org/words.txt"
WORDS = []
PHRASES = {
}
然后是对读取的文件名以及解析语种进行检验,if语句,len长度是检验是否输入文件中含有两个变量,以及满足使用英语作为语言的要求
if len(sys.argv) == 2 and sys.argv[1] == "english":
PHRASE_FIRST = True
else:
PHRASE_FIRST = False
这段为从网络上下载数据,使用导入的urlopen函数,关于urlopen函数
函数原型如下:urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
直接用urllib.request模块的urlopen()获取页面,page的数据格式为bytes类型,需要decode()解码,转换成str类型。所以与解码语言匹配上了,上述使用的英语。采用readline依次读行
#load up the words form the website
for word in urlopen(WORD_URL).readlines():
WORDS.append(str(word.strip(), encoding = "utf-8"))
str为字符串类型,str函数为掐头去尾函数,str() 函数将指定的值转换为字符串。语法如下:
str(object, encoding=encoding, errors=errors)
定义转化函数
##这个函数把首字母变大写 capitalize(),其他小写,把w中的第一个字符变为大写
#sample函数,从列表里抽几个,这边的几个是这段文字出现了几个“%%%”,然后以list形式返回,count()函数为统计这一段文字中出现括号内文文字的个数。
将results和param作为空的list等待添加
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 = []
然后开始函数内部循环
这是第一个层次的,param_count为随机数,param_names中添加了肉干个随机例子
for i in range(0, snippet.count("@@@")):
param_count = random.randint(1,3)
param_names.append(', '.join(
random.sample(WORDS, param_count)))
第二个层次的循环
result等于sentence这个list的切片,然后通过区分这个语句属于哪一类,分别对语句进行替换,再把这个句子加到results里面去。最后返回results这个列表
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
最后进入try语句,如果是代码未出错,则会一直执行下去,否则跳出至except,正确条件如下,则执行对snippets中的所有元素随机排序,然后调用convert函数
try:
while True:
snippets = list(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)
input("> ")
print(f"ANSWER: {answer}\n\n")
except EOFError:
print("\nBye")
———————————————————————————————————————————
练习42 对象和类
直接写在注释里了
##Animal is-a object (yes,sort of confusing)look at the extra credit
class Animal(object):
pass
##占位因为如果定义一个空函数程序会报错,当你没有想好函数的内容是可以用 pass 填充,使程序可以正常运行
##定义狗是Animal的一个子类
class Dog(Animal):
def __init__(self, name):
##他的初始函数包括他自己的属性,以及具有name的属性
self.name = name
##同理
class Cat(Animal):
def __init__(self, name):
self.name = name
##定义一个不同于object的新类
class Person(object):
def __init__(self, name):
##他的初始函数包括他自己的属性,以及具有name的属性
self.name = name
##这样确保 self.pet 这个类的属性被设为默认的 None。
self.pet = None
##employee属于person的一个子类,多了一薪水属性
class Employee(Person):
def __init__(self, name, salary):
##运行父类的 init ,从父类中继承
super(Employee, self).__init__(name)
##定义salary属性
self.salary = salary
##定义鱼类
class Fish(object):
pass
##定义这啥玩意儿我也不知道
class Salmon(object):
pass
##定义一个哈利波特类
class Halibut(object):
pass
##rover is-a Dog
Rover = Dog("Rover")
##Satan is-a Cat
Satan = Cat("Satan")
##Mary is-a Person
Mary = Person("Mary")
##Mary has-a cat,pet属性的值为Satan
Mary.pet = Satan
##Frank is-a employee,属性salary为12000
Frank = Employee("Frank", 120000)
##同mary
Frank.pet = Rover
##
Flipper = Fish()
##??
Crouse = Salmon()
##??
Harry = Halibut()
———————————————————————————————————————————
练习43比较复杂还没玩明白,先看个练习44
———————————————————————————————————————————
练习44
子类和父类以及继承组合关系,肖恩是这么写的,主要有隐式、显式、覆盖后调用三种方式,他的核心如下。
-
子类上的操作会覆盖父类上的操作。
-
子类上的操作会更改父类上的操作。
-
对子类的行为意味着对父类的行为。
隐式继承:
在类中声明,child是parent的一个子类,即子类可以调用父类中的操作,父类定义了一个implicit函数,它同样对子类适用
class Parent(object):
def implicit(self):
print("PARENT implicit()")
class Child(Parent):
pass
dad = Parent()
son = Child()
dad.implicit()
son.implicit()
#即使我在第 16 行调用了 son.implicit(),并且 Child 里面也没有定义一个隐式函数
#它仍然可以正常运行,它调用了在 Parent 中定义的那个函数
#这表明如果将函数放在基类中(比如 Parent),然后所有子类(比如 Child)会自动获得这些特性。
#对于需要写很多重复代码的类来说非常方便。
显式继承:
虽然child是parent的一个子类,但是他在调用同名函数中定义自己的版本来重写override函数
class Parent(object):
def override(self):
print("PARENT override()")
class Child(Parent):
def override(self):
print("CHILD override()")
dad = Parent()
son = Child()
dad.override()
son.override()
#分别定义自己的版本来写函数
修改前后
同样是定义两个类,定义两个同名函数,但是定义子类中多定一个altered函数,它调用了super,这个super获得了parent.altered版本,可以把他理解为,它意识到需要继承,并会为你获取 Parent 类。你应该能够把这个理解为“使用参数 Child 和 self 来调用 super,然后在它返回的任何地方调用 altered 函数”。Parent.altered 版本的函数运行,并打印出 Parent 的信息。
class Parent(object):
def altered(self):
print("PARENT altered()")
class Child(Parent):
def altered(self):
print("CHILD, BEFORE PARENT altered()")
super(Child, self).altered()
print("CHILD, AFTER PARENT altered()")
dad = Parent()
son = Child()
dad.altered()
son.altered()
super()与init初始化
class Child (Parent):
def __init__(self, stuff):
self.stuff = stuff
super(Child, self).__init__( )
直接继承父类,和上面的child.altered很像