“笨办法”学Python 3 ——练习41学着去说面向对象

练习41 学着去说面向对象

面向对象的基本用词:

1. 词汇练习
self :在一个类的函数里面,self 是被访问的实例/对象的一个变量。
继承(inheritance) :关于一个类能从另一个类那里继承它的特征的概念,很像你和你的父母。
组合(composition) :关于一个类可以由其他一些类构成的概念, 很像一辆车包含几个轮子。
属性(attribute) :类所拥有的从组合那里得到的特性,通常是变量。
is-a :一种用来表达某物继承自一种东西的表述, 就像“三文鱼是一种鱼”
has-a :一种用来表达某物是由一些东西组成或具有某种特性的表述,就像“三文鱼有一个嘴巴”。
2. 短语训练
class X(Y) :创建一个名为 X 并继承自 Y 的类。
class X(object): def __init__(self, J) : 类 X 有一个带有 self 和 J 参数的 init 函数。
class X(object): def M(self, J):类 X 有一个带有 self 和 J 参数的 M 函数。
foo = X():设 foo 为类 X 的一个实例。
foo.M(J):从 foo 那里获取 M 函数,并用 self 和 J 参数来调用它。
foo.K = Q:从 foo 那里获取 K 属性,并设它为 Q。(K是类里面的变量)

练习源代码

输入:

#random模块提供生成伪随机数的函数
import random
#urlib.request模块打开和浏览URL,其中urlopen()函数,打开url网站
from urllib.request import urlopen  
import sys

WORD_URL = "http://learncodethehardway.org/words.txt" #内容所在的url网站
WORDS =[] #创建空列表,存储URL中读取的单词

PHRASES = {
    "class %%%(%%%):":
    "Make a class named %%% that is-a %%%.",
    "class %%%(object):\n\tdef __init__(self,***)":
    "class %%% has-a __init__ that takes self and ***params.",
    "class %%%(object):\n\tdef ***(self,@@@)":
    "class %%% has-a function *** that takes self and @@@ params.",
    "*** = %%%()":
    "Set *** to a instance of class %%%.",
    "***.***(@@@)":
    "From *** get the *** function, call it with params 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": 
#sys.argv的参数列表数量为2 且 参数列表的第二个参数为'english'时
#此脚本未定义argv列表的数量,所以数量可以外部随意输入
    PHRASE_FIRST = True
else:
    PHRASE_FIRST = False

# load up the words from the website
#(从网站加载单词)
#urlopen打开网址URL, 返回值始终为一个对象,并按行读取
for word in urlopen(WORD_URL).readlines():
    #删除word字符串开头或结尾的空格,并转化字符串格式,添加值WORDS列表
    WORDS.append(str(word.strip(), encoding = "utf-8"))

#定义函数convert(转换),参数为snippet(一条):字符串,phrase(词汇):字符串。
def convert(snippet, phrase):
    #定义列表变量class_names(类名),根据count()函数计算'%%%'数量,并以此为依据随机截取WORDS列表。
    #w.capitalize(),将字符串的开头小写字母更改为大写字母
    class_names = [w.capitalize() for w
    in random.sample(WORDS, snippet.count("%%%"))]
    other_names = random.sample(WORDS,snippet.count("***")) #截取WORDS列表的随机数列表,数目为'***'的数量。
    results = [] #空列表,用于存储替换字符串后,面向对象术语的解
    param_names = [] #空列表,用于存储类中函数的参数名

    #for循环,循环次数为"@@@"的数量
    for i in range(0, snippet.count("@@@")):
        param_count = random.randint(1,3) #1到3之间的整数,包括1和3。
        #根据param_count的数目截取WORDS的随机数列表,并转化为字符串用","连接,并添加到列表。
        param_names.append(", ".join(random.sample(WORDS, param_count))) 
    
    #for循环,变量sentence,序列snippet,phrase两个字符串,遍历的方式就是将两个字符串转化到变量中,得到一个字符串列表。
    for sentence in snippet, phrase:  
        result = sentence[:] #复制列表
        print(result)#调试加的
        
        #fake class names(伪装类名)
        for word in class_names:  #for循环,遍历class_names的列表
            result = result.replace("%%%", word, 1)#替换字符串,旧字符"%%%",新字符=word变量的值,替换一个字符

        #fake other names(伪装其他名称)
        for word in other_names:
            result = result.replace("***", word, 1) #同上,只是新字符为other_names中的词
        
        #fake parameter lists(伪装参数列表)
        for word in param_names:
            result = result.replace("@@@", word, 1) #同上,新字符为param_names中的词
        
        results.append(result) #添加至results列表
   # print(results)
    return results #函数convert()返回值为results

# keep going until they hit CTRL-D 继续运行直到点击CTRL-D
#try....except: 用来检测 try 语句块中的错误,从而让 except 语句捕获异常信息并处理
try:
    while True:
        snippets = list(PHRASES.keys()) #定义变量snippets为列表,且内容为字典PHRASE的键。
        random.shuffle(snippets) #打乱snippets列表元素顺序

        for snippet in snippets:  #for循环,以PHRASE字典键的数量和内容循环
            phrase = PHRASES[snippet] #变量为PHRASES字典对应键的值
            question, answer = convert(snippet, phrase) #定义变量,对应值为convert()函数返回值results列表中的元素。
            if PHRASE_FIRST: #判断PHRASE_FIRST的值,若为True则进行,否则跳过
                question, answer = answer, question  #对调question和answer的值

            print(question) #打印question

            input("> ") #输入question对应的结果
            print(f"ANSWER: {answer}\n\n") #打印结果,并换两行运行,课余自己输入的结果做对比。
except EOFError:
    print("\nBye")

输出结果:
#输出结果是随机的,第一种输出方式:

#输入python ex41.py
crush.credit(cellar)
> From crush get credit function, call it with params self cellar. #input内容,根据问题回答
ANSWER: From crush get the credit function, call it with params self cellar. #对比自己的回答是否正确

#会不断循环输出不同的内容
class Cattle(object):
        def __init__(self,cave)
>
#Ctrl + C停止运行

第二种输出方式,加english,输出的问题和答案会与第一种输出方式颠倒一下。

#输入python ex41.py english
Make a class named Cobweb that is-a Calculator.
> Class Cobweb(Calculator):
ANSWER: class Cobweb(Calculator):

#会不断循环输出不同的内容
class Coil has-a function boot that takes self and bike, alarm params.
>
#Ctrl + C停止运行

代码相关知识点

1.urllib是一个包,收集几个模块来处理网址。
urllib.request打开和浏览url中内容。urllib.request模块定义了方法和类,帮助打开url(主要是HTTP)。
urllib.request.urlopen()函数
(1)作用:
打开网址URL, 返回值始终为一个对象,并可以调用相应的方法获取返回的信息。

(2)函数语法:

urllib.request.urlopen(url, data=None)

其中:url:资源url,data:携带的数据。

2.random模块:
random模块提供生成伪随机数的函数。
(1)random.randint(m,n)
用于生成一个指定范围内的整数。其中参数a是下限,参数b是上限,生成的随机数n: a <= n <= b。
例如:

#输入
import random
for i in range(4):
    num = random.randint(3,7) #随机生成整数
    print(num)

#输出,结果随机
3
4
6
6

(2)random.sample(sequence,count)
截取列表的指定长度的随机数。sample函数不会修改原有序列。
例如:

#输入
import random
a =[]
for n in range(2,8):
    a.append(n+1)
print(a)
print(random.sample(a,4)) #截取序列a的4个随机数,序列a不变

#输出:
[3, 4, 5, 6, 7, 8]
[8, 5, 3, 4]

(3)random.shuffle(list)
将一个列表内的元素顺序打乱,随机排列,使用这个方法不会生成新的列表,只是将原列表的次序打乱。
例如:

#输入
import random
str = ['you','are','a','beautiful','girl']
random.shuffle(str) #随机打乱列表顺序
print(str)

#输出
['girl', 'are', 'a', 'beautiful', 'you']

3.sys模块,argv()函数
sys是 “system”,是一个系统模块是与python解释器交互的一个接口,提供了许多函数和变量来处理 Python 运行时环境的不同部分。
“argv” 即 “argument value” 是一个列表对象,其中存储的是在命令行调用 python 脚本是提供的 “命令行参数”。
sys.argv[0] 表示程序自身
sys.argv[1] 表示程序的第一个参数
sys.argv[2] 表示程序的第二个参数
以此类推。
我目前所遇到的有两种写法:
第一种,在脚本中指定argv参数,外部输入的参数数目固定

#输入
from sys import argv
Script, name = argv #定义函数argv列表参数,则外部输入时,参数数量是固定的
print(Script,name)

#输出
#终端输入text41.py lily
text41.py lily

第二种,脚本内不定义argv函数的参数列表

#输入
import sys
print(f"the first argv is ", sys.argv[0])
print(f"other argv is/are ",sys.argv[1:]) #不定义argv列表

输出
# 终端输入:python text41.py egg 1 2 pig
the first argv is  text41.py
other argv is/are  ['egg', '1', '2', 'pigC:/Users/***/Anaconda3/python.exe', 
'c:/Users/***/Desktop/Python3_exercises/text41.py'] #最后应该是表示文件所在位置的路径,也打印了出来

4.strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符。

5.capitalize()函数:
只是针对于开头是小写字母的字符串,对于其他的任何情况都将失效。该方法返回一个首字母大写的字符串。
语法:

str.capitalize()

示例:

#输入
方法1(借鉴本练习的代码):
words = ['drug', 'drum', 'duck', 'dust']
words_c1 = [word.capitalize() for word in random.sample(words, len(words))] 
print(words_c1)

#方法2,基础的编写
#上面的编写方法是下面编写方法的变种
words_c2 = []
for w in random.sample(words,len(words)): #截取words列表的长度的随机数列表,因此列表顺序与原列表顺序不同。
    words_c2.append(w.capitalize())
print(words_c2)

输出结果:

['Drug', 'Duck', 'Drum', 'Dust']
['Duck', 'Dust', 'Drug', 'Drum']

6.count()函数:
用于统计字符串里某个字符或子字符串出现的次数。
语法:str.count(sub, start= 0,end=len(string))
参数含义:
sub – 搜索的子字符串
start – 字符串开始搜索的位置。默认为第一个字符,第一个字符索引值为0。
end – 字符串中结束搜索的位置。字符中第一个字符的索引为 0。默认为字符串的最后一个位置。
示例:
参考练习的源代码

#count()函数
PHRASES = {
    "class %%%(%%%):":
    "Make a class named %%% that is-a %%%.",
    "class %%%(object):\n\tdef __init__(self,***)":
    "class %%% has-a __init__ that takes self and ***params.",
    "class %%%(object):\n\tdef ***(self,@@@)":
    "class %%% has-a function *** that takes self and @@@ params.",
    "*** = %%%()":
    "Set *** to a instance of class %%%.",
    "***.***(@@@)":
    "From *** get the *** function, call it with params self @@@.",
   " ***.*** = '***'":
   "From *** get the *** attribute and set it to '***'."
   } #创建字典

snippets = list(PHRASES.keys()) #转化为列表
print(snippets) #打印列表
num_list = [] #空列表,存储snippets列表中每个字符串元素snippet的'%%%'数量
for snippet in snippets:
    num_count = snippet.count('%%%')
    num_list.append(num_count)
print(num_list)

输出结果:

['class %%%(%%%):', 'class %%%(object):\n\tdef __init__(self,***)', 'class %%%(object):\n\tdef ***(self,@@@)', '*** = %%%()', '***.***(@@@)', " ***.*** = '***'"]
[2, 1, 1, 1, 0, 0]

5.replace()函数
用于对字符串中的元素进行替换,返回新的字符串,不对原字符串修改。
语法:

String.replece(old, new, count)

参数:
old:字符串中要被替换的字符
new:新的字符
count:替换几个字符,从左向右遍历
注意点:
参数大小写区分
如果原字符串中没有指定的旧字符串,则原样输出。
示例:

#replace()函数用法
ws = ["123","word","apple","pc"] #列表
result = "class %%%(%%%):" #字符串
#for循环的简写,并随机获取ws列表中同%%%数量相同的词汇
names = [w for w in random.sample(ws,result.count('%%%'))] 
#使用for循环替换result中的%%%字符串
for n in names:
    result = result.replace("%%%", n, 1) 
print(result)

输出结果:

class word(pc):

附加练习

1. 需要继续读更多的代码,并在这些代码中复习你之前学过的短语。
自行练习

常见问题

1. result = sentence[:] 是干什么用的? 这是 Python 复制一个列表的方式。它用的是列表的切片(slice)语法 [:],能够很快地创建一个从第一个元素到最后一个元素的列表切片。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值