首页 > 代码库 > Python基础知识

Python基础知识

如果想对Python语言有一个基本的了解,那么可以把它想象成伪代码,因为两者很相似。变量没有类型,所以不需要声明。变量在赋值的时候出现,不再使用的时候则会消失。赋值使用=运算符完成,像下面这样:

x = 42

注意,相等性的检测是由==运算符完成的。

还可以一次对多个变量进行赋值:

x, y, z = 1, 2, 3

first, second = second, first

a = b = 123

语句块通过并且只通过缩进表示(没有begin/end语句或者括号)。下面是一些普通的控制结构:

if x < 5 or (x > 10 and x < 20):

print “The value is OK.”

if x < 5 or 10 < x < 20:

print “The value is OK”

for i in [1, 2, 3, 4, 5]:

print “This is iteration number”, i

x = 10

while x >=0:

print “x is still not negative.”

x = x - 1

前面2个例子是等价的。

for循环中的索引变量会迭代列表(本例中使用方括号写成)中的元素。为了实现“普通的”for循环(也就是计数循环),可以使用内建的range函数:

#打印0~99的值,包括099

for value in range(100):

print value

#开头的行是注释,会被解释器忽略。

现在(在理论上)已经介绍了python内实现算法的大部分内容了。接下来增加一些基本的用户交互。为了(从文本提示符)获取用户的输入,可以使用内建的input函数:

x = input(“Please enter a number: “)

print “The sqare of that number is “, x*x

input函数会显示(可选的)给定提示符,并且让用户输入任何合法的Python值。本例中,我们期望的是数字。如果输入了其他的类型值(比如字符串),程序会以一个错误信息终止。为了避免出现这种情况,需要增加一些错误检查机制。这里我先不介绍。我们先假设想让程序将用户的输入以字符串形式逐字地返回(这样就可以输入任何值了),可以使用raw_input函数。如果想要将输入字符串s转换为整数,可以使用int(s)

                                                                               注意 如果想要使用input输入一个字符串,那么用户就需要显式地写出引号。在Python

     中,字符串可以用单、双引号括起。在Python 3.0 中,原始的input方法被取消了。                              raw_input被重命名为input.

刚刚介绍了控制结构、输入和输出了,现在来看“华丽”的数据结构。其中最重要的是列表和字典。列表的元素写在中括号中间,可以(很自然地)进行嵌套:

name = [“Cleese”, “John”]

x = [[1, 2, 3], [y, z],[[[]]]]

列表最棒的地方之一在于可以单独访问它的元素,也可以通过索引以及分片分组访问。索引访问(和其他多数语言一样)是在列表后加上以中括号括起的索引值实现的(注意,第一个元素的索引为0)。

print name[1], name[0] #Prints  “John Cleese”

name[0] = “Smith”

分片基本上和索引一样,不过可以表示结果的起始和结束索引,使用冒号(:)进行分隔:

x = [“SPAM”, “SPAM”, “SPAM”, “SPAM”, “SPAM”, “eggs”, “and”, “SPAM”]

print x[5:7] #Prints the list [“eggs”, “and”]

注意,结尾索引是不包含在结果内的。如果不写明两个索引中的一个,那么程序会假定需要哪个方向上的所有元素。换句话说,分片x[:3]意为“x中从开始到3号元素之间的所有元素,不包括3号元素”(也可以说表示第4个元素,因为是从0开始计数的)。分片x[3:]则表示“x中从3号元素(包括)开始到结尾之间的所有元素”。真正有意思的是,分片操作也可以使用负数:x[-3]是列表倒数第三个元素。

现在说说字典。简单来说,它们类似于列表,但它们的内容是无序的。那么怎么进行索引呢?每个元素都有一个键,或者名称,它用类似于真正字典的方式查找元素。下面的例子演示了用于创建字典的语法:

phone = {“Alice”: 23452532, “Boris”: 252336,

  “Clarice”: 2352525, “Doris”:23624643 }

person = {‘first name’: “Robin”, ‘lastname’: “Hood”,

   ‘occupation’: “Scoundrel”}

现在要获得person的职业(occupation)的话,可以使用表达式person[“occupation”].如果想要改变姓,可以像下面这样做:

person[‘last name’] = “of Locksly”

很简单吧?字典类似于列表,也可以包含其他字典。当然,字典也可以包含列表。同样地,列表也能包含字典。这样一来就可以轻松创建一些很高级的数据结构。

函数

下一步是抽象。这个过程类似于给一段代码起个名字,并且利用一些参数调用它。换句话说,就是定义一个函数,也叫做过程(procedure)。很简单,像下面这样使用关键字def:

def square(x):

return x*x

print square(2) #打印4

return语句用于从函数返回值

在向一个函数传递参数时,同时就将参数绑定到了值上,因而也就创建了新的引用。这意味着可以在函数内部直接修改原始的值。但是如果将参数名引用到了其他值上面(重绑定),那么这个修改就不会影响到原来的变量。这种工作方式类似于Java.让我们看下面这个例子:

def change(x):

x[1] = 4

y = [ 1, 2, 3]

change(y)

print y  #Print out [ 1, 4, 3]

你看到了,传入的是原始列表,如果函数对其进行了修改,那么这些修改也会传递到调用函数的地方。不过请注意下面例子的行为,函数体重绑定了参数:

def nochange(x):

x = 0

y = 1

nochange(y)

print y #打印1

为什么y没变?因为函数没有改变这个值!传入的值是1,不能像更改列表那样更改一个数字。数字1就是(也永远是)数字1。我所做的是改变参数x的引用,这样不会影响到调用。

Python有各种各样的参数,例如命名的参数(named argument)和默认值参数(default argument,它们可以处理一个函数的多个参数。

如果知道如何使用函数,那么刚才所讲到的基本上就是在Python内需要知道的。

不过了解Python的函数是值”这个概念可能会比较有用。如果有一个square的函数,那么可以像下面这样做:

queeble = square

print queeble(2) #打印4

为了能不用参数调用函数,必须记得要写成doit( )而不是doit。后者只会将函数本身作为值返回。对于对象中的方法也是如此。

对象和相关内容

Python中,可以使用class关键字定义类,像下面这样:

#不要忘记self参数

def __init__(self, content=None):

self.contents = contents or [ ]

def add(self, element):

self.contents.append(element)

def print_me(self):

result = “ “

for element in self.contents:

result = result + “ “ +repr(element)

print “Contains:” + result

    上面的例子有些值得注意的方面。

□方法这样调用:object.method(arg1, arg2)。

□有些参数是可选的,并且被赋予了默认值,通过像下面这样定义函数而实现:

def spam(age=32): ...

□这里的spam可以使用1个或0个参数调用。如果不使用参数进行调用,那么参数age 会使用默认值32。

□repr函数将对象转换为它的字符串表达形式(如果element包括数字1,那么 reprc(element)就等同于“1”,这里的“element”是字符量字符串。)。

Python内的方法或者成员变量(特性)都是无保护的(也不是私有的)。封装更像是一种编程风格(如果真的需要,也可以使用一些命名约定实现私有化,不如使用单或双下划线作为名称前缀)。

现在来谈谈短路逻辑······

Python内所有的值都可以用作逻辑值。那么空值,比如False、[]、0、“”或者None表示逻辑假,而其他的值(比如True、[0]、和“Hello, world”)表示逻辑真。

逻辑表达式,比如a and b是这样计算的。

□检查a是否为真。

□如果答案是否定的,那么直接返a。

□如果为真,那么直接返回b(表示表达式中的真值)。

□相应的a or b的逻辑是这样的。

□如果a为真,那么返回a。

□否则返回b。

短路机制让你可以像实现布尔运算符那样使用and或者or,同时也允许程序员编写短小精干的条件表达式。比如如下语句:

if a:

print a

else:

print b

可以写为如下形式:

print a or b

事实上,这是Python的一种习惯用语,最好还是能习惯它。

 

注意  Python 2.5 中,已经引入了真正的条件表达式,所以你可以写成这样一种形式:print a if a else b。

Basket构造函数(Basket.__into__)使用这个策略处理默认参数。参数contonts的默认值是None(也就是假),那么要检查它是否包含一个值的时候,可以写成如下形式:

if  contents:

self.contents = contents

else:

self.contents = [ ]

而构造函数只用了一条语句:

self.contents = contents or [ ]

为什么不把[ ]的默认值放在前面呢?这是Python工作方式的原因,它会给所有Basket实例赋予一个同样的空列表作为默认内容。某个实例开始填充数据,它们会包含同样的元素,而默认的也不再是空列表。

 

注意  Basknet.__into__等方法使用None作为占位符时,使用content isNone作为条件比只检查参数的布尔值要安全,因为这样做允许传入类似于空列表这样的假值(到对象外可以保留一个引用的地方)。

 

如果将空列表作为默认值使用,像下面做这样避免在实例间共享内容的问题:

def __into__(self,contents=[ ]):

self.content = content[:]

能猜到它是如何工作的吗?并不是每个地方都使用同一个空列表,而是使用contents[:]表达式创建一个副本(也就是对整个列表进行分片)。

那么为了创建一个Basket对象并且使用它(调用它的一些方法),可以像下面这样做:

b = Basket([‘apple’,‘orange’])

b.add(“lemon”)

b.print_me( )

这样会打印Basket的内容——一个apple(苹果)、一个orange(橘子)和一个lemon(柠檬)。

除了__init__外还有一些魔方方法。比如__str__方法,它定义对象作为字符串时候的输出。可以用它来替代print_me:

def __str__(self)

result = “”

for element in self.contents:

result = result + “” +repr(element)

return “Contains:” + result

如果想要打印b的内容,那么只要像下面这样:

print b

很酷吧?

像下面这样实现子类化(继承):

class SpamBasket(Basket):

# ...

Python允许多继承,所以可以在圆括号内用逗号隔开多个超类。类像这样初始化:x=Basket( )。而构造函数像我说过的一样,通过定义特殊的成员函数__init__而得到。假设SpamBasket有一个__init__(self,type)构造函数,那么就能像这样实现一个SpamBasket对象:y = SpamBasket(“apples”)。

如果在SpamBasket的构造函数中需要调用一个或多个超类的构造函数,可以像这样调用:Basket.__init__(self).注意,除了要提供一般的参数外还要显式地提供self参数,因为超类的__init__不知道它正在处理那个实例。

其他琐碎知识

大多数有用的函数和类都在模块中,它们是真正的以.py作为扩展名并包括Python代码的文本文件。读者可以在自己的程序中导入进行使用,比如要使用标准模块math中的sqrt函数,即可以像下面这样编写代码:

import math

x = math.sqrt(y)

也可以像下面这样:

from math import sqrt

x = sqrt(y)

所有模块/脚本内的代码都会在导入的时候运行。如果想让你的程序既是可以导入的模块,又是可以运行的程序,可以再末尾加入下面这行:

if __name__ == “__main__”:main( )

这个方法很奇妙,如果模块作为可执行脚本运行(也就是并不导入到其他脚本中),那么函数main会被调用。当然可以在main函数内做任何事。

而如果想要在UNIX内创建可执行脚本的话,可以使用下面这行代码让脚本自己运行:

#!/usr/bin/env python

最后,简单地介绍一个重要概念:异常。有些操作(类似于除0或者从不存在的文件中读取数据)会产生一个错误状况,或者说异常。你可以创建自定义异常,让它们在适当的时间引发它们。

如果对于异常什么都不做,程序会结束,并且打印错误信息。不过可以使用try/except语句避免这种情况。比如:

def safe_division(a, b):

try:

return a/b

except ZeroDivisionError:pass

ZeroDivisionError是个标准的异常。本例中,可以检查b是否为0,但是很多情况下这个方法行不通。除此之外,如果在self_division中移动try/except语句的话,会让它变成一个调用时带有风险的函数(就变成unsafe_division了),仍然可以像下面这样做:

try:

unsafe_division(a, b)

except ZeroDivisionError:

print “Somethings was divided by zero in unsafe_division”

本例中一般来说不会看到具体的问题,但是它可能会发生,使用异常可以避免将时间浪费在无谓的测试上。

 

Python基础知识