Python算法的分享(二)

输入与输出

程序经常需要与用户进行交互,以获得数据或者提供某种结果。目前的大多数程序使用对话框作为要求用户提供某种输入的方式。尽管Python确实有方法来创建这样的对话框,但是可以利用更简单的函数。Python提供了一个函数,它使得我们可以要求用户输入数据并且返回一个字符串的引用。这个函数就是input。

input函数接受一个字符串作为参数。由于该字符串包含有用的文本来提示用户输入,因此它经常被称为提示字符串。举例来说,可以像下面这样调用input。

aName = input('Please enter your name: ')

不论用户在提示字符串后面输入什么内容,都会被存储在aName变量中。使用input函数,可以非常简便地写出程序,让用户输入数据,然后再对这些数据进行进一步处理。例如,在下面的两条语句中,第一条要求用户输入姓名,第二条则打印出对输入字符串进行一些简单处理后的结果。

aName = input("Please enter your name ")
print("Your name in all capitals is ",aName.upper(),
      "and has length", len(aName))

需要注意的是,input函数返回的值是一个字符串,它包含用户在提示字符串后面输入的所有字符。如果需要将这个字符串转换成其他类型,必须明确地提供类型转换。在下面的语句中,用户输入的字符串被转换成了浮点数,以便于后续的算术处理。

sradius = input("Please enter the radius of the circle ")
radius = float(sradius)
diameter = 2 * radius
格式化字符串

print函数为输出Python程序的值提供了一种非常简便的方法。它接受零个或者多个参数,并且将单个空格作为默认分隔符来显示结果。通过设置sep这一实际参数可以改变分隔符。此外,每一次打印都默认以换行符结尾。这一行为可以通过设置实际参数end来更改。下面是一些例子。

>>> print("Hello")
Hello
>>> print("Hello","World")
Hello World
>>> print("Hello","World", sep="***")
Hello***World
>>> print("Hello","World", end="***")
Hello World***>>>

更多地控制程序的输出格式经常十分有用。幸运的是,Python提供了另一种叫作格式化字符串的方式。格式化字符串是一个模板,其中包含保持不变的单词或空格,以及之后插入的变量的占位符。例如,下面的语句包含is和years old.,但是名字和年龄会根据运行时变量的值而发生改变。

print(aName, "is", age, "years old.")

使用格式化字符串,可以将上面的语句重写成下面的语句。

print("%s is %d years old." % (aName, age))

这个简单的例子展示了一个新的字符串表达式。%是字符串运算符,被称作格式化运算符。表达式的左边部分是模板(也叫格式化字符串),右边部分则是一系列用于格式化字符串的值。需要注意的是,右边的值的个数与格式化字符串中%的个数一致。这些值将依次从左到右地被换入格式化字符串。

让我们更进一步地观察这个格式化表达式的左右两部分。格式化字符串可以包含一个或者多个转换声明。转换字符告诉格式化运算符,什么类型的值会被插入到字符串中的相应位置。在上面的例子中,%s声明了一个字符串,%d则声明了一个整数。其他可能的类型声明还包括i、u、f、e、g、c和%。表1-9总结了所有的类型声明。

格式化字符串可用的类型声明

在这里插入图片描述

可以在%和格式化字符之间加入一个格式化修改符。格式化修改符可以根据给定的宽度对值进行左对齐或者右对齐,也可以通过小数点之后的一些数字来指定宽度。表1-10解释了这些格式化修改符。

格式化修改符

在这里插入图片描述

格式化运算符的右边是将被插入格式化字符串的一些值。这个集合可以是元组或者字典。如果这个集合是元组,那么值就根据位置次序被插入。也就是说,元组中的第一个元素对应于格式化字符串中的第一个格式化字符。如果这个集合是字典,那么值就根据它们对应的键被插入,并且所有的格式化字符必须使用(name)修改符来指定键名。

>>> price = 24
>>> item = "banana"
>>> print("The %s costs %d cents" % (item,price))
The banana costs 24 cents
>>> print("The %+10s costs %5.2f cents" % (item,price))
The     banana costs 24.00 cents
>>> print("The %+10s costs %10.2f cents" % (item,price))
The     banana costs     24.00 cents
>>> itemdict = {"item":"banana","cost":24}
>>> print("The %(item)s costs %(cost)7.1f cents" % itemdict)
The banana costs    24.0 cents
>>>

除了格式化字符串可以使用格式化字符和修改符之外,Python的字符串还包含了一个format方法。该方法可以与新的Formatter类结合起来使用,从而实现复杂字符串的格式化。可以在Python参考手册中找到更多关于这些特性的内容。

控制结构

正如前文所述,算法需要两个重要的控制结构:迭代和分支。Python通过多种方式支持这两种控制结构。程序员可以根据需要选择最有效的结构。

对于迭代,Python提供了标准的while语句以及非常强大的for语句。while语句会在给定条件为真时重复执行一段代码,如下所示。

>>> counter = 1
>>> while counter <= 5:
...     print("Hello, world")
...     counter = counter + 1
...

Hello, world
Hello, world
Hello, world
Hello, world
Hello, world

这段代码将“Hello, world”打印了5遍。Python会在每次重复执行前计算while语句中的条件表达式。由于Python本身要求强制缩进,因此可以非常容易地看清楚while语句的结构。

while语句是非常普遍的迭代结构,我们在很多不同的算法中都会用到它。在很多情况下,迭代过程由复合条件来控制。

while counter <= 10 and not done:

在这个例子中,迭代语句只有在上面两个条件都满足的情况下才会被执行。变量counter的值需要小于或等于10,并且变量done的值需要为False(not False就是True),因此True and True的最后结果才是True。

while语句在众多情况下都非常有用,另一个迭代结构for语句则可以很好地和Python的各种集合结合在一起使用。for语句可以用于遍历一个序列集合的每个成员,如下所示。

>>> for item in [1,3,6,2,5]:
...    print(item)
...
1
3
6
2
5

for语句将列表[1,3,6,2,5]中的每一个值依次赋给变量item。然后,迭代语句就会被执行。这种做法对任意的序列集合(列表、元组以及字符串)都有效。

for语句的一个常见用法是在一定的值范围内进行有限次数的迭代。下面的语句会执行print函数5次。range函数会返回一个包含序列0、1、2、3、4的范围对象,然后每个值都会被赋给变量item。接着,Python会计算该值的平方并且打印结果。

>>> for item in range(5):
...    print(item**2)
...
0
1
4
9
16
>>>

for语句的另一个非常有用的使用场景是处理字符串中的每一个字符。下面的代码段遍历一个字符串列表,并且将每一个字符串中的每一个字符都添加到结果列表中。最终的结果就是一个包含所有字符串的所有字符的列表。

>>> wordlist = ['cat','dog','rabbit']
>>> letterlist = []
>>> for aword in wordlist:
...    for aletter in aword:
...       letterlist.append(aletter)
...
>>> letterlist
['c', 'a', 't', 'd', 'o', 'g', 'r', 'a', 'b', 'b', 'i', 't']
>>>

分支语句允许程序员进行询问,然后根据结果,采取不同的行动。绝大多数的编程语言都提供两种有用的分支结构:ifelse和if。以下是使用ifelse语句的一个简单的二元分支示例。

if n < 0:
   print("Sorry, value is negative")
else:
   print(math.sqrt(n))

在这个例子中,Python会检查n所指向的对象是否小于0。如果是,就会打印一条消息,说明它是负值;如果不是,就会执行else分支来计算它的平方根。

和其他所有控制结构一样,分支结构支持嵌套,一个问题的结果能帮助决定是否需要继续问下一个问题。例如,假设score是指向计算机科学考试分数的变量。

if score >= 90:
   print('A')
else:
   if score >= 80:
      print('B')
   else
      if score >= 70:
         print('C')
      else:
         if score >= 60:
            print('D')
         else:
            print('F')

这一代码段通过打印字母等级来对变量score进行分类。如果分数大于或等于90,这一语句会打印A;如果小于90(else),会接着问下一个问题。如果分数大于或等于80,因为小于90,所以它一定介于80和89之间,那么语句就会打印B。可以发现,Python的缩进模式帮助我们在不需要额外语法元素的情况下有效地关联对应的if和else。

另一种表达嵌套分支的语法是使用elif关键字。将else和下一个if结合起来,可以减少额外的嵌套层次。注意,最后的else仍然是必需的,它用来在所有分支条件都不满足的情况下提供默认分支。

if score >= 90:
   print('A')
elif score >= 80:
   print('B')
elif score >= 70:
   print('C')
elif score >= 60:
   print('D')
else:
   print('F')

Python也有单路分支结构,即if语句。如果条件为真,就会执行相应的代码。如果条件为假,程序会跳过if语句,执行下面的语句。例如,下面的代码段会首先检查变量n的值是否为负。如果值为负,那么就取它的绝对值,再计算它的平方根。

if n < 0:
   n = abs(n)
print(math.sqrt(n))

列表可以通过使用迭代结构和分支结构来创建。这种方式被称为列表解析式。通过列表解析式,可以根据一些处理和分支标准轻松创建列表。举例来说,如果想创建一个包含前10个完全平方数的列表,可以使用以下的for语句。

>>> sqlist = []
>>> for x in range(1,11):
         sqlist.append(x*x)
>>> sqlist
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>>

使用列表解析式,只需一行代码即可创建完成。

>>> sqlist = [x*x for x in range(1,11)]
>>> sqlist
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>>

变量x会依次取由for语句指定的1到10为值。之后,计算x*x的值并将结果添加到正在构建的列表中。列表解析式也允许添加一个分支语句来控制添加到列表中的元素,如下所示。

>>> sqlist = [x*x for x in range(1,11) if x%2 != 0]
>>> sqlist
[1, 9, 25, 49, 81]
>>>

这一列表解析式构建的列表只包含1到10中奇数的平方数。任意支持迭代的序列都可用于列表解析式。

>>>[ch.upper() for ch in 'comprehension' if ch not in 'aeiou']
['C', 'M', 'P', 'R', 'H', 'N', 'S', 'N']
>>>

异常处理

在编写程序时通常会遇到两种错误。第一种是语法错误,也就是说,程序员在编写语句或者表达式时出错。例如,在写for语句时忘记加冒号。

>>> for i in range(10)
SyntaxError: invalid syntax (<pyshell#61>, line 1)

在这个例子中,Python解释器发现,由于语句不符合Python语法规范,因此它无法执行这条指令。初学者经常会犯语法错误。

第二种是逻辑错误,即程序能执行完成但返回了错误的结果。这可能是由于算法本身有错,或者程序员没有正确地实现算法。有时,逻辑错误会导致诸如除以0、越界访问列表等非常严重的情况。这些逻辑错误会导致运行时错误,进而导致程序终止运行。通常,这些运行时错误被称为异常。

许多初级程序员简单地把异常等同于引起程序终止的严重运行时错误。然而,大多数编程语言都提供了让程序员能够处理这些错误的方法。此外,程序员也可以在检测到程序执行有问题的情况下自己创建异常。

当异常发生时,我们称程序“抛出”异常。可以用try语句来“处理”被抛出的异常。例如,以下代码段要求用户输入一个整数,然后从数学库中调用平方根函数。如果用户输入了一个大于或等于0的值,那么其平方根就会被打印出来。但是,如果用户输入了一个负数,平方根函数就会报告ValueError异常。

>>> anumber = int(input("Please enter an integer "))
Please enter an integer -23
>>> print(math.sqrt(anumber))
Traceback (most recent call last):
  File "<pyshell#102>", line 1, in <module>
    print(math.sqrt(anumber))
ValueError: math domain error
>>>

可以在try语句块中调用print函数来处理这个异常。对应的except语句块“捕捉”到这个异常,并且为用户打印一条提示消息。

>>> try:
       print(math.sqrt(anumber))
    except:
       print("Bad Value for square root")
       print("Using absolute value instead")
       print(math.sqrt(abs(anumber)))

Bad Value for square root
Using absolute value instead
4.79583152331
>>>

except会捕捉到sqrt抛出的异常并打印提示消息,然后会使用对应数字的绝对值来保证sqrt的参数非负。这意味着程序并不会终止,而是继续执行后续语句。

程序员也可以使用raise语句来触发运行时异常。例如,可以先检查值是否为负,并在值为负时抛出异常,而不是给sqrt函数提供负数。下面的代码段显示了创建新的RuntimeError异常的结果。注意,程序仍然会终止,但是导致其终止的异常是由我们自己手动创建的。

>>> if anumber < 0:
...    raise RuntimeError("You can't use a negative number")
... else:
...    print(math.sqrt(anumber))
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
RuntimeError: You can't use a negative number
>>>

除了RuntimeError以外,还可以抛出很多不同类型的异常。请查看Python参考手册,了解完整的异常类型以及如何自己创建异常。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值