Thinking in Python(前言 + Python语言概览)

Thinking in Python

Design Patterns and Problem-Solving Techniques

 

Bruce Eckel

President, MindView, Inc.

 

前言

本书中所用的资料开始于我在最近几年中所做的Java联合研讨会,有几次是跟Larry O’Brien, 还有Bill VennersBill和我重复了好几次这样的研讨会,并且在这几年中,我们根据对模式新的理解以及召开研讨会的经验,对这些资料进行了数次更改。

在这个过程中,我们都积累了足够多的信息可以来举办自己独立的学术研讨会,我们都不想这么做的一个主要因素是,我们可以从一起举办研讨会这件事情中得到如此多的乐趣。我们曾经在美国的大部份地方举办过这样的讲座,还有布拉格(我们还想尝试每个春天都在那儿举办这样的一个小型讲座,以及很多其它的讲座。)但我们只做了偶尔几次这样的现场讲座,因为我们有2个人,所以花费也较多,并且比较难于统一计划时间表。

非常感谢在这些年中来参加讲座的人们,当然包括LarryBill,因为他们帮助我实现这些想法并改进它们。我希望我能够通过这本书跟相关的讲座,在接下来的很多年中继续形成并发展这样的想法。

本书也不会一直停止在这个状态,最初,这些资料是一本C++图书的一部份,然后是Java图书,之后就停止在基于Java的图书上,最后,在长时间的考虑之后,我决定最好的开始来创建我自己在设计模式方面论点集的办法是,首先用Python写下它们(因为我们都知道Python是最理想的原型语言!),之后再将相关的内容转换为Java版本。将想法首先在一个比较强大的语言上进行实践,之后再转换到其它语言,在这方面我也已经积累了一些经验,而且我也发现这样做可以更容易看透问题并保持一个清晰的概念。

所以Thinking in Python这本书,最初的时候,是从Thinking in Patterns for Java移植过来的,而不是一本介绍Python语言的书(书店中有很多针对这个好语言的介绍与学习的书籍)。我认为现在这样的一本书籍会比一本普通的语言教程更令人激动(当然只好向那些希望得到一本语言教程的人说对不起了)。

 

针对程序员的Python快速教程

本书假定你是一个有经验的程序员,最好你已经通过其它书籍学习过Python语言。对于那些没有学习过Python的人,本章将对此语言给出一个快速介绍。

 

Python概述

本简介针对有经验的程序员(我想正在读本书的人都会是的)。你可以从www.python.org得到所有的文档信息(特别是A Python Quick Reference部分),也可以阅读很多其它的书籍,如Learning Python,作者是Mark LutzDavid AscherO’Reilly, 1999)。

Python经常被当成是一种脚本语言,但是脚本语言通常受限于它们的问题域。Python,从另一个角度来说,是一种支持脚本的编程语言。在这方面它出奇地强大,你可以用它来代替所有的批处理文件,命令行脚本,以及一些简单的程序。但是它远远不至只是一种脚本语言。

Python被设计成非常清晰的书写格式,特别是针对源代码的阅读。你会发现隔很长时间后,你还是可以轻松地阅读与理解这些代码,不管是你自己写的还是其它人写的。这部分得益于简洁,扼要的语法,但是主要的因素的易读性因素是代码的缩进格式代码段在Python中都通过缩进来标识。例如:

 

#: c01:if.py

response = "yes"

if response == "yes":

  print "affirmative"

  val = 1

print "continuing..."

#:~

 

符号’#’表示从此开始到行尾属于注释部分,就像是C++Java’//’符号。

首先注意到在Pythonif语句是C风格的。但是在Cif语句中,你必须要用括号来括起条件部分,而在Python中它们是不需要的(如果你用了括号,将不能通过编译)。

条件子句用冒号来结束,这表明紧跟的是一组缩进语句,是if语句中的then部分。在这个例子中是一条print标准输出语句,之后是对一个名字为val的变量的赋值。再往下的代码不再缩进,表示它们不再是if语句的一部分。缩进可以无限嵌套,就像是C++Java中的大括号,但是在Python中它们不需要也不必要出现,编译器强制所有的代码都按同样的方式进行格式化,这也是Python代码符合可读性的主要原因。

通常情况下,Python中一行只有一条语句(你也可以在一行上放置多行语句,并用分号;来分隔),语句的结尾也不再需要表示结束的分号。即使在上面的小例子中,你也可以看到Python语言被设计成尽可能地简单,并保持可读性。

内建容器

 

C++Java这样的语言,容器都是由附加的类库来提供,而不集成在语言中。在Python中,编程使用的容器在本质上被集成到语言的核心中:ListArray(如Map, Dictionary, Hash-table)都是基本数据类型。这样做在极大程度上提高了语言本身的优雅性。

另外,for语句也被设计为自动在列表中进行迭代,而不是通过一个计数器来循环。这是很有意思的事,因为我们几乎总是使用一个for的步进循环来处理一个数组或容器。Python通过自动使用一个针对序列的迭代器来实现它。下面是一个例子:

 

#: c01:list.py

list = [ 1, 3, 5, 7, 9, 11 ]

print list

list.append(13)

for x in list:

  print x

#:~

第一行创建了一个列表,你可打印这个列表,结果看起来就跟你往列表中赋值的形式一样。ListJava中对应的容器一样你可以添加新的元素(使用append()),它们会自动调整容器的大小。for语句创建了一个迭代子x用来从列表中取出每一个值。

你也可以通过range()函数来创建一个数字列表,这样你也可以模仿C中的for.

注意到,这里没有任何类型声明对象名只是简单地出现,Python将会通过你使用它们的方式来推断它们的类型。这也说明Python被设计为你只需要按下那些必需的键来进行编程,你在以前已经被太多的非Python语言要求写下冒号,大括号等等所有的冗长的无用代码,而这些对于描述你的程序想要做什么是没有任何帮助的。

 

函数

要在Python中创建一个函数,你要使用def关键字,之后是函数名与参数列表,并用一个冒号来开始函数体。下面是第一个函数例子:

 

#: c01:myFunction.py

def myFunction(response):

  val = 0

  if response == "yes":

    print "affirmative"

    val = 1

  print "continuing..."

  return val

 

print myFunction("no")

print myFunction("yes")

#:~

注意到在函数签名中没有任何类型信息它只指定了函数的名字与参数标识符,没有参数类型与返回类型。Python是一种弱类型语言,这说明它只要求最少的打字工作。例如,你可以在同一个函数中传递并返回不同的类型:

 

#: c01:differentReturns.py

def differentReturns(arg):

  if arg == 1:

    return "one"

  if arg == "one":

    return 1

 

print differentReturns(1)

print differentReturns("one")

#:~

唯一的约束是,对于传入函数的对象,必须要能应用在函数中对它所进行的操作,其它的都不需要关心。在这里,同一个函数对intstring同样都应用了‘+’操作。

 

#: c01:sum.py

def sum(arg1, arg2):

  return arg1 + arg2

 

print sum(42, 47)

print sum('spam ', "eggs")

#:~

当对string应用操作符’+’时,它意味着连接它们(当然,Python支持操作符重载)。

 

String

上面的例子介绍了一点点Python操作string的情况,而且是我所见过的语言中做得最好的。你可以用单引号或双引号来表示string,这样做的好处就是,当你用双引号来表示string时,你就可以在string中包含单引号作为普通的字符。

 

#: c01:strings.py

print "That isn't a horse"

print 'You are not a "Viking"'

print """You're just pounding two

coconut halves together."""

print '''"Oh no!" He exclaimed.

"It's the blemange!"'''

print r'c:/python/lib/utils'

#:~

请注意Python这个名字不是来自于一条蛇,而是一部叫做Monty Python的喜剧。

 

用三个引号可以括起所有的东西,包括新的行。这就让一些处理特别地方便,如产生Web页面(Python是一种特别好的CGI语言),因为你可以用三引号来括起整个页面而不用其它的编辑。

string前面的r表示‘原始未加工的’,如对于’/’来说,你就不需要用‘//’来表示一个’/’了。

String中的替换也是特别的简单,因为Python使用Cprintf()替换语法,且针对所有的string类型。只要在string后加上’%’,再跟上需要替换的值就行了。

 

#: c01:stringFormatting.py

val = 47

print "The number is %d" % val

val2 = 63.4

s = "val: %d, val2: %f" % (val, val2)

print s

#:~

就像你在第二个例子中见到的,如果有超过一个参数,你只要简单地用括号括起来就可以了(这实际上构成了一个tuple,一个不能修改的list—当然你也可以用常规的list来处理,只是通常情况下,我们都使用tuple)。

printf()提供的所有格式化功能都是可用的,包括控制小数的位数以及对齐方式等等。Python还提供了非常强大的正则表达式功能。

 

Python中所有其它东西一样,类的定义只需要使用最少量额外的语法。你可以使用关键字class,在类的主体部分使用def来定义方法。下面是一个简单的例子:

 

#: c01:SimpleClass.py

class Simple:

  def __init__(self, str):

    print "Inside the Simple constructor"

    self.s = str

  # Two methods:

  def show(self):

    print self.s

  def showMsg(self, msg):

    print msg + ':',

    self.show() # Calling another method

 

if __name__ == "__main__":

  # Create an object:

  x = Simple("constructor argument")

  x.show()

  x.showMsg("A message")

#:~

所有的方法都将self作为他们的第一个参数。在C++Java中,对于类方法,也都拥有隐藏的第一个参数,他指向方法被调用的对象,并且可以通过this关键字进行访问。Python也使用这样的一个针对当前对象的引用,只是在你声明一个方法时,你必须明确的地将此引用指定为第一个参数。习惯上,这个引用被称作self,但是你可以用任何你想使用的标识符(如果你不使用self,可能会让好多人感到疑惑)。如果你想要引用对象的字段或其它的方法,则必须要在表达式中使用self。然而,当你在调用对象的方法时,如x.show(),你不需要特别处理针对此对象的self引用这都自动完成了。

在这里,第一个方法是个特殊的方法,就是名称标识符以双下划线开始并结束的方法。在这个情况下,它定义了一个构造器,它在对象创建时自动被调用,跟C++Java一样。然而,在示例代码的最后部分,你可以看到创建了一个对象,看起来就像是使用类名来调用一个函数。Python简洁的语法可以让你认识到根本不需要像在C++Java中能看到得新的关键字。

所有在底部的代码都由一个if条件进行调用,此条件检测名为__name__的变量是否等于__main__。再强调一次,有双下划线出现的地方就表示一个特殊的名字。使用此if语句的原因是任何文件都可以被当成一个库由其它一个程序调用(很快将会讲到模块)。在这种情况下,你只是想使用定义好的类,并不想执行在文件底部的代码。这个特殊的语句只有在你直接执行此文件的情况下才为真,就像下面这样在命令行上输入:

Python SimpleClass.py

然而,若这个文件由另一个程序作为一个模块引入,则__main__代码就不会被执行。

最初,你会感到有些比较意外的东西,就是你只在类方法中定义字段,而不像C++Java中那样在方法之外定义(若你使用C++/Java方式来定义字段,它们就会隐含地成为static字段)。要创建一个对象字段,你只要命名它使用self引用只任何一个方法中(通常是在构造函数中,但并不总是),当这个方法被调用后,相应的内存空间就被创建出来了。这跟C++/Java相比看起来有点奇怪,在它们中,你必须首先决定你的对象需要占用多少空间,但现在,这种新的方法为编程提供了一个非常灵活的结果。

 

继承

因为Python是弱类型语言,所以它不会关心接口所有它关心的只有应用到对象上操作(实际上,Javainterface关键字在Python中是多余的)。这意味着在Python中继承与C++/Java中通过继承来建立一个公共接口的目的是不同的。在Python中,继承唯一的理由就是继承一个实现那重用基类中的代码。

如果你准备继承一个类,你必须告诉Python将这个类带入你的新文件中。Python使用与Java类似的方式来控制它的名字空间。只要你创建一个文件,你就隐含地创建了一个与文件同名的模块(就像是Java中的一个包),因而,在Python中不需要package关键字。当你想要使用一个模块时,你只要使用import,并给出模块的名字。Python将会搜索PYTHONPATH,就像Java会搜索CLASSPATH一样(但是由于一些原则,Python不会有Java中的一些缺陷),并读入此模块。要访问一个模块中的函数或类,你只要给出模块名,一个’.’,再加上函数或类的名字。如果你不想被名字限制符所困扰,你可以给出:

from module import name(s)

这里name(s)可以是用逗号分隔的一组名字。

你可以通过在类名后的括号中列出类(或一组类,Python支持多重继承)的名字来实现继承。同时,请注意Simple类,它存在于名字为SimpleClass的文件(也就是模块)中,通过import被带入到新的名字空间中来。

 

#: c01:Simple2.py

from SimpleClass import Simple

 

class Simple2(Simple):

  def __init__(self, str):

    print "Inside Simple2 constructor"

    # You must explicitly call

    # the base-class constructor:

    Simple.__init__(self, str)

  def display(self):

    self.showMsg("Called from display()")

  # Overriding a base-class method

  def show(self):

    print "Overridden show() method"

    # Calling a base-class method from inside

    # the overridden method:

    Simple.show(self)

 

class Different:

  def show(self):

    print "Not derived from Simple"

 

if __name__ == "__main__":

  x = Simple2("Simple2 constructor argument")

  x.display()

  x.show()

  x.showMsg("Inside main")

  def f(obj): obj.show() # One-line definition

  f(x)

  f(Different())

#:~

Simple2Simple中继承得到,在构造器中,调用了基类的构造器。在display()方法中,showMsg()可以被作为self的一个方法进行调用,但是在你调用被覆盖的基类方法时,你必须要使用带限制符的函数名,并将self作为第一个参数,就像调用基类构造器时所做的那样,在覆盖版本的show()方法中也调用了基类的show()方法。

__main__中,运行程序,你将会看到基类构造器被调用的过程,同时也可以看到继承类中的showMsg()方法被调用,一切都跟我们期望的继承行卫一致。

 

 

The class Different also has a method named show( ), but this class is not derived from Simple. The f( ) method defined in __main__ demonstrates weak typing: all it cares about is that show( ) can be applied to obj, and it doesn’t have any other type requirements. You can see that f( ) can be applied equally to an object of a class derived from Simple and one that isn’t, without discrimination. If you’re a C++ programmer, you should see that the objective of the C++ template feature is exactly this: to provide weak typing in a strongly-typed language. Thus, in Python you automatically get the equivalent of templates – without having to learn that particularly difficult syntax and semantics. Add Comment

 

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值