14: 方法

到目前为止我们已经看到了Python中的几种数据结构:字符串和序列。它们每个都支持几种方法,这也是方程的变体形式。

例如,list中的一个方法reverse()。从名字上就可以看出来,这个方法可以颠倒这个序列(也就是说,第一项放在最后一项,最后一项放在第一项)。你需要使用一个(.)来使用此方法,结构如下:

«objectName».«methodName»(«list of arguments, if any»)

相比之下,我们已经见到的使用方程的句法是

«functionName»(«list of arguments, if any»)

下面这个例子是在序列上使用reverse 的方法。

示例
颠倒一个序列。

这有一个方法的例子,它带有一个实参str. startswith:

示例
一些字符串方法。

多种方法

在下面,我们会提到最普遍的字符串和序列方法。这些方法大多都能通过你自己写的程序代替,但是使用标准的方法会让代码更便于阅读和编辑。

序列

这些方法不会更改序列:

  • list.index(X): 寻找序列中的X。具体来说,这个方法返还i,其中list[i]==X通过搜索序列中所有的项返还最小的i。如果X在序列中不存在,会发生ValueError
    • 如果X是序列中的项,X in list返还True,否则False。使用这个会避免ValueErrorin是一个运算符,而不是一个方法)。
  • list.count(X): 返还X在序列中出现的次数

示例
序列方法。

这些方法会改变序列:

  • list.append(X)X加到list
  • list.insert(i, X)X加到位置 i
  • list. extend (L)在结尾加上一个序列L
  • list.remove(X)移除第一次出现的X
  • list.pop(i)删除& 返还list[i],而list.pop()删除& 返还最后一项
  • del list[i]删除序列list中第i项(注意,这是一个"del statement",不是一个方法)
  • list.reverse()颠倒序列
  • list.sort()将序列排序

上述所有的方法除了pop,都返还None。其中一些带有些许不同实参的方程也可以被调用;详见Python中的序列方法。序列也支持复杂的子范围,名为"slices",允许整个子范围的插入和删除,类似于我们在previous 中所看见的string[x:y:z]

编程练习: 替换
使用index和其他的序列方法,编写一个程序replace(list, X, Y),用Y替换序列list中的所有X。例如,如果L = [3, 1, 4, 1, 5, 9],那么replace(L, 1, 7)会改变L,使其变为[3, 7, 4, 7, 5, 9]。为了使这个练习更具挑战性,你不能使用 [ ]。
注意:你不需要使用returnHint

字符串

就像序列一样,你可以对字符串使用inindexcount。这些更加方便,因为他们也对子链适用,并不仅仅是找到单个的字符:

  • S in T是一个布尔值,判断是否字符串S是字符串T的子链
  • S.index(T)找到S中子链T第一次出现的的第一个字母的索引
  • S.count(T)返还S的子链T不重叠出现的次数

示例
对字符串使用indexcount

下面是一些有用的str方法:

  • 字母: capitalize, lower, upper, islower, isupper
  • 字符: isalpha, isdigit
  • Padding: center, ljust, rjust; strip 会消除padding
  • 子链: endswith, startswith, find, replace
  • 分解: split, splitlines

我们会在需要的时候更详细的介绍这些方法。完整详细的字符串方法列表会
在Python 文档中给出。

字符串是不可更改的。我们提到过list.reverse()可以颠倒一个序列,但是没有str.reverse()方法。这是因为字符串一旦被创建就不能被更改。在第17课中我们会做以解释。

这是一个字符串方法的例子:S.replace(old, new)返还一个更改过的S,所有的子链old被更换成new。这会创建一个新的字符串,而不是更改以前的字符串:

示例
例子:replace返还新的字符串,不更改原来的字符串。

下面的这些方法对下一个练习会有所帮助:

  • str.replace,我们刚介绍过
  • 布尔方法str.isalpha(),如果str是一个只由字母组成的字符串(或字符),返还True
  • 布尔方法str.isdigit(),如果str是一个只由数字组成的字符串(或字符),返还True
  • str.upper()返还str的大写形式。

编程练习: Exact Postage
定义一个方程postalValidate(S),首先查看S是否代表有效的邮政编码:

  • 首先,删除所有的空格;
  • 剩下的形式一定是L#L#L#,其中L是字母(不论大小写),#是数字。

如果S不是有效的邮政编码,返还布尔值False。如果S 有效,以L#L#L#的形
式,返还相同的邮政编码,其中每个L都是大写。

这节课剩余的部分有点技术性,余下的课程对这方面知识并没有要求。

更多对象

随着对Python 的深入学习,你会发现除了字符串和序列以外的更多的类型。其他一些你可能觉得有用的东西包括文件对象集合字典。它们都有很多有用的方法。你可以通过使用dir方程列出Python中一个对象的所有的方法:

示例
str的方法。注意startswith是其中的一个输出。

查看对象的性质被称作反省。Python中所有的东西都可以有方法:

示例
int的成员。

一些dir中的项实际上是member variables而不是方法,例如int.denominator是一个数字,不是一个方程。严格来说,方程是Python中的对象,所以子方程是子变量中的特殊例子。

你也可以对模块进行反省。如果你先下令import math,然后下令dir(math),按后你就会得到一序列math模块中所有的东西, 包括数字pi和方程sqrt

为什么要有对象?

为什么我们有类似于S.index(T)的方法,而不是一个简单的方程index(S, T)?换句话说,为什么我们有对象 S方法 str.index()

当你开始对更复杂的,不同种数据进行编程的时候,对象的主要优势会显现出来。每一种对象(比如,str、class)不仅代表可以被储存的数据(比如,一系列字符和长度),还代表可以在其上进行运算的类型(比如,转换为大写或产生子链)。一个更复杂的例子是文件对象:他们代表被打开的文件名字,你现在在文件中的位置,以及阅读,写的方法。你甚至可以定义你自己的数据类型!

这个通常的方法被称为"面向对象的编程" (OOP)。其中的一些好处是:

  • 机构math模块中的所有东西都可以通过math.«name»句法得到,避免在程序中重复写已经存在的变量名字。
  • 封装: 就像是一个能同时对几个字符串或几个文件进行处理的程序一样,你可以对很多由其他类别定义的不同的数据类型进行处理。
  • 重复使用: 一旦你定义了一个数据类型(比如str)或一个方法库(比如math),你可以重复使用它,或把它给其他人使用。
  • 调试: 早些时候,我们看到了如何编写一些方程来预防拥有近似代码的副本,从而使调试更简单。编写一个位置对应一个数据的所有的方程(种类定义)可以起到相同的效果。
  • 种类间的关系: Python知道index方法对于字符串来说是一个意思,对于序列来说是别的意思。同样的,Python不仅可以在你的电脑上读取并书写文档,也可以在网络上读取并书写数据。在这两个情况中(字符或序列顺序,本地或远程文件),相关的种类可以用同一种方式解决。那就是通过使用inheritance的概念。

在剩下的CS Circles课程中,我们只会使用对象和方法;你可以自行了解更多有关创建自己独有的种类的信息(查看资源网页)。

接下来的三节课可以按任何顺序完成,会有一系列结合之前课程主题的问题。