从第一台计算机问世起,编程逐渐走进大家的生活。对外行人来说,编程就是学会一门计算机语言。

几乎所有编程语言中都会出现以下几类基本指令。

● 输入:从键盘、文件或者其他设备中获取数据。

● 输出:将数据显示到屏幕,保存到文件中,或者发送到网络上等。

● 数学:进行基本数学操作,如加法或乘法。

条件执行:检查某种条件的状态,并执行相应的代码。

● 重复:重复执行某种动作,往往在重复中有一些变化。

但是学会计算机语言就算是编程了吗?

并不是,编程是一个非常复杂的工作,需要不断分解,把大的任务分解成小的基础任务,然后再由上面这些基本指令组合完成。

易语言给python写界面 易语言 python_易语言给python写界面

Python语言一直以来都以简单易学而深受程序员喜欢,但学习Python语言,除了要掌握基础语言,更重要的是学会编程思维,将编程作为工具去达到更高的目标。

今天就给大家分享一个简单的案例,了解一下如何利用编程思想,分解问题,并实现问题。

文字游戏

文字游戏讲述的是通过搜索具有某种特性的单词来解决单词谜题这一话题。例如,我们会寻找英语单词中最长的回文单词,还会搜索那些其字母按照字母表顺序排列的单词。另外,我会介绍另一种程序开发计划:缩减问题规模,回归成之前解决过的问题。

1、 读取单词列表

准备一个英文单词列表,(这里引用的是Grady Ward收集整理并作为Moby词典项目的一部分贡献给公共域的)文件名为words.txt。

这个文件是纯文本,所以可以使用文本编辑器打开,也可以使用Python读入它。内置函数open接收文件名作为参数,并返回一个文件对象(file object),可以用来读取文件。

>>> fin = open('words.txt')

fin是用来表示文件对象作为输入源时常用的名称。文件对象提供了几个方法用于读取内容,包括readline,它会从文件里读入字符,直到获得换行符为止,并将读入的结果作为一个字符串返回:

>>> fin.readline()'aa'

在这个特定的列表中,第一个单词是"aa",它是一种火山熔岩。序列表示两个空格字符,一个是回车,一个是换行,用于把这个单词和其他单词分隔开。

文件对象会记录它读到文件的哪个位置,因此如果再次调用readline,会得到下一个单词:

>>> fin.readline()'aah'

下一个单词是"aah",也是一个完全合法的单词,所以别用奇怪的眼光看着我。或者,如果是那几个空白字符在干扰你,可以使用字符串的方法strip去掉它们:

你也可以在for循环中使用文件对象。下面的代码读入words.txt并每行打印出一个单词:

fin = open('words.txt')for line in fin:   word = line.strip()   print(word)

2、 搜索

前面一节的所有练习都有一个共同点;它们可以使用搜索模式来解决。最简单的例子是

def has_no_e(word):   for letter in word:     if letter == 'e':        return False   return True

for循环遍历单词word中的字符。如果我们找到字母“e”,可以立即返回False;否则只能继续下一个字母。如果正常退出了循环,则说明我们没有找到“e”,所以返回True。

使用in操作符,可以把这个函数写得更简洁。上面这个示例没有写得更简洁是因为想要展现搜索模式的逻辑。

avoids是has_no_e的更通用的版本,它们的结构相同:

def avoids(word, forbidden):   for letter in word:     if letter in forbidden:        return False   return True

一旦发现一个禁止的字母,可以立即返回False;如果运行到循环结束,则返回True。

uses_only函数也类似,只是它条件判断的意思是相反的:

def uses_only(word, available):   for letter in word:     if letter not in available:        return False   return True

它接收的参数并不是一个禁止字母列表,而是一个可用字母列表available。如果我们发现单词中遇到了并不属于available的字母,则可以返回False。

uses_all函数也类似,但单词和字母列表的角色相反。

def uses_all(word, required):   for letter in required:     if letter not in word:        return False   return True

我们不再遍历单词word中的字母,而是循环遍历必需的单词列表required。如果单词列表中有任意字母没有出现在单词中,我们可以返回False。

如果你真的像计算机科学家那样思考的话,应该已经发现,uses_all实际上是已经解决的问题的一个特例,并且可以这么写:

def uses_all(word, required):   return uses_only(required, word)

这是被称为将问题回归到已解决问题(reduction to a previously solved problem)的程序开发计划的一个例子。意即你需要识别出的当前问题是一个已经解决的问题的特例,从而可以直接利用现有的解决方案。

3、 使用下标循环

在前面一节的例子中,我使用for循环进行遍历,因为只需要字符串中的字符,而不需要操作下标。

但对is_abecedarian函数我们需要比较相邻的字母,使用for循环比较困难:

def is_abecedarian(word):   previous = word[0]   for c in word:     if c

或者也可以使用递归:

def is_abecedarian(word):   if len(word) <= 1:     return True   if word[0] > word[1]:     return False   return is_abecedarian(word[1:])

还有一个办法是使用while循环:

def is_abecedarian(word):   i = 0   while i

循环开始于i=0,并结束于i=len(word)-1。每次迭代时,比较第i个字符(可以看成是当前字符)和第i+1个字符(可以看成是下一个字符)。

如果下一个字符比当前字符小(即按照字母顺序在前),则我们发现了一个破坏字母顺序的断点,可以返回False。

如果我们没有找到任何断点而结束循环,则这个单词通过了测试。为了说服自己循环是正确结束的,可以考虑像'flossy'这样的例子。这个单词的长度是6,所以最后一次循环时i是4,即是倒数第二个字符的下标。在最后一个循环中,会比较倒数第二个和最后一个字符,这正是我们所期待的。

下面是is_palindrome函数(参考练习 6-3)的一个版本,它使用两个下标;一个从0开始递增;另一个从最后开始递减。

def is_palindrome(word):   i = 0   j = len(word)-1   while i

或者,我们可以将其回归到已经解决的问题,可能这么写:

def is_palindrome(word):   return is_reverse(word, word)

4、 调试

测试程序很难。本章中的函数相对容易测试,因为可以简单地手动验证结果。即便如此,要选择一组可以测试到所有可能的错误的单词,也是很困难的,甚至是不可能的。

举has_no_e作为例子,有两个很明显的用例可以检测:包含“e”的单词应该返回False;不包含“e”的应当返回True。为这两种情况找到具体的单词没有问题。

但对每种情况来说,也存在一些不那么明显的具体情况。在所有包含“e”的单词中,你应当测试以“e”开头的单词,也应当测试以“e”结尾,以及“e”在单词中部的情况。你应当测试长单词、短单词及非常短的单词,如空字符串。空字符串是特殊情形(special case)的一个例子。特殊情形往往不那么明显,但又常常隐藏着错误。

除了自己生成的测试用例之外,还可以使用类似words.txt这样的单词表来测试你的程序。通过扫描输出,可能会发现错误,但请注意:你可能发现一种类型的错误(不应该被包含但却被包含的单词),但对另一种类型的则不能发现(应该被包含,但却没有出现的单词)。

总之,测试可以帮助你发现bug,但生成一组好的测试用例并不容易。而且,即使有好的测试用例,也无法确定程序是完全正确的。引用一个传奇计算机科学家的话:

程序测试可以用来显示bug的存在,但无法显示它们的缺席!(Program testing can be used to show the presence of bugs,but never to show their absence!)

文件对象(file object):用来表示一个打开的文件的值。

将问题回归到已解决问题(reduction to a previously solved problem):通过把问题表述为已经解决的某个问题的特例解决问题的一种方式。

特殊情形(special case):一种不典型或者不明显(因此更可能没有正确处理)的测试用例。

高效编程的小技巧

Python虽然语法简单,入门门槛比较低,但是想要用好Python,熟练运用于各个领域,用它解决复杂的问题,开发功能正确、效率高的程序,同样会遇到很多的问题。

刚刚我们提到编程思维需要将大的问题分解成小的任务,除此之外,编程思维其实还可以让我们找到完成任务更高效的技巧和方法。

今天通过一个案例分享高效编程的小技巧:以问题、解决方案和讨论相结合的方式将序列分解为单独的变量。

第一步列出问题

我们有一个包含 N 个元素的元组或序列,现在想将它分解为N个单独的变量。

第二步解决方案

任何序列(或可迭代的对象)都可以通过一个简单的赋值操作来分解为单独的变量。唯一的要求是变量的总数和结构要与序列相吻合。例如:

>>> p = (4, 5)>>> x, y = p>>> x4 >>> y5 >>>>>> data = [ 'ACME', 50, 91.1, (2012, 12, 21) ]>>> name, shares, price, date = data>>> name'ACME'>>> date(2012, 12, 21)>>> name, shares, price, (year, mon, day) = data>>> name'ACME'>>> year2012>>> mon12>>> day21>>>

如果元素的数量不匹配,将得到一个错误提示。例如:

>>> p = (4, 5)>>> x, y, z = pTraceback (most recent call last):  File "", line 1, in ValueError: need more than 2 values to unpack>>>

第三步讨论

实际上不仅仅只是元组或列表,只要对象恰好是可迭代的,那么就可以执行分解操作。这包括字符串、文件、迭代器以及生成器。比如:

>>> s = 'Hello'>>> a, b, c, d, e = s>>> a'H'>>> b'e'>>> e'o'>>>

当做分解操作时,有时候可能想丢弃某些特定的值。Python并没有提供特殊的语法来实现这一点,但是通常可以选一个用不到的变量名,以此来作为要丢弃的值的名称。例如:

>>> data = [ 'ACME', 50, 91.1, (2012, 12, 21) ] >>> _, shares, price, _ = data >>> shares 50 >>> price 91.1 >>>

但是请确保选择的变量名没有在其他地方用到过。