/*鼠标点击特效*/

python基础教程(第3版)

Python程序员会熟悉文件对象的方法: readline ()、write()、read()等。Python库支持文件和文件类对象。Socket对象则不提供类似的接口,您或许会觉得这样不是很方便。然而Python的确提供了一个makefile ( )函数来生成供您使用的文件类对象。

Python 的socket模块实际上定义了4种可能出现的异常:

  1. 与一般I/O 和通信问题有关的socket.error;
  2. 与查询地址信息有关的socket.gaierror;
  3. 与其他地址错误有关的socket.herror(和C语言中的h_errno相关
  4. 与在一个socket上调用settimeout ()后,处理超时有关的socket.timeout(需要Python2.3或更高版本)。

快速上手:基础知识

1.1 交互式解释器

Python 3.5.0 (default, Dec 5 2015, 15:03:35) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.1.76)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>>

如果你熟悉其他计算机语言,可能习惯了在每行末尾都加上分号。在Python中无需这样做,
因为在Python中,一行就是一行。如果你愿意,也可加上分号,但不会有任何影响(除非后面还
有其他代码),况且大家通常都不这样做。

1.2 算法是什么

1.3 数和表达式

交互式Python解释器可用作功能强大的计算器

除法运算的结果为小数,即浮点数(float或floating-point number)。

>>> 1 / 2 
0.5 
>>> 1 / 1 
1.0

如果你想丢弃小数部分,即执行整除运算,可使用双斜杠。

>>> 1 // 2 
0 
>>> 1 // 1 
1 
>>> 5.0 // 2.4 
2.0

在较旧的Python版本中,对整数执行常规除法运算的结果与使用双斜杠类似。
如果你使用的是Python 2.x,要对整数执行常规除法运算,可在程序开头添加如下语句(稍后介绍如何编写完
整的程序),也可直接在交互式解释器中执行这条语句:

>> from __future__ import division

另外,从命令行运行较旧的Python版本时,还可使用命令行开关-Qnew。1.8.2节将更详尽地
介绍__future__。
关于版本的问题,“future”目的是把下一个版本的特性导入到当前版本,这样我们就可以在当前版本中测试一些新版本的特性,从而使得python未来版本的迁移更加容易。
future语句必须在靠近模块开头的位置出现。只有以下内容可以放在future语句之前。
1、模块的文档字符串
2、注释
3、空行
4、其他future语句

即x % y 等价于x - ((x // y) * y)。
这种运算符甚至可用于负数,但可能不那么好理解。

>>> 10 % 3 
1 
>>> 10 % -3 
-2 
>>> -10 % 3 
2 
>>> -10 % -3 
-1

C语言遵循了尽量让商尽量靠近0的原则,两个异号的数取余之后的结果取决于分子的符号
然而,在Python中,取余的计算公式与别的语言并没有什么区别:r=a-n*[a//n]
这里r是余数,a是被除数,n是除数。
不过在“a//n”这一步,当a是负数的时候,会向下取整,也就是说向负无穷方向取整。这也就得到:
两个异号的数取余之后的结果取决于分母的符号
C跟分子;
python跟分母

请注意,乘方运算符的优先级比求负(单目减)高,因此-32等价于-(32)。如果你要计
算的是(-3)**2,必须明确指出。

十六进制数、八进制数和二进制数分别以下面的方式表示:

>>> 0xAF 
175 
>>> 010 
8 
>>> 0b1011010010 
722

这些表示法都以0打头。

1.4 变量

使用Python变量前必须给它赋值,因为Python变量没有默认值。

1.5 语句

1.6 获取用户输入

你编写的程序可能供他人使用,无法预测用户会向程序提供什么样的值。我们来看看很有用
的函数input(稍后将更详细地介绍函数)。

>>> input("The meaning of life: ") 
The meaning of life: 42 
'42'

这里在交互式解释器中执行了第一行(input(...)),它打印字符串"The meaning of life:",
提示用户输入相应的信息。我输入42并按回车。这个数被input(以文本或字符串的方式)返回,
并在最后一行被自动打印出来。通过使用int将字符串转换为整数,可编写一个更有趣的示例:

>>> x = input("x: ") 
x: 34 
>>> y = input("y: ") 
y: 42 
>>> print(int(x) * int(y)) 
1428
  • 先睹为快:if语句
>>> if 1 == 2: print('One equals two') 
... 
>>> if 1 == 1: print('One equals one') 
... 
One equals one 
>>> 

需要注意的另一点是,在交互式解释器中输入if语句后,需要按两次回车键才能执行它 (其中的原因将在第5章介绍)。

1.7 函数

1.3节使用了乘方运算符(**)来执行幂运算。实际上,可不使用这个运算符,而使用函数pow。

>>> 2 ** 3 
8 
>>> pow(2, 3) 
8

有多个内置函数可用于编写数值表达式。例如,abs计算绝对值,round将浮点数圆整为与之
最接近的整数。

>>> abs(-10) 
10 
>>> 2 // 3 
0 
>>> round(2 / 3) 
1.0

请注意最后两个表达式的差别。整数总是向下圆整,而round圆整到最接近的整数,并在两
个整数一样近时圆整到偶数。如果要将给定的数向下圆整,该如何做呢?例如,你知道某人的年
龄为32.9,并想将这个值向下圆整为32,因为他还没有满33岁。Python提供了完成这种任务的函
数floor,但你不能直接使用它,因为像众多很有用的函数一样,它也包含在模块中。

1.8 模块

可将模块视为扩展,通过将其导入可以扩展Python功能。要导入模块,可使用特殊命令
import。前一节提及的函数floor包含在模块math中。

>>> import math 
>>> math.floor(32.9) 
32

请注意其中的工作原理:我们使用import导入模块,再以module.function的方式使用模块
中的函数。就这里执行的操作而言,也可像前面处理input的返回值那样,将这个数字转换为
整数。

>>> int(32.9) 
32

还有一些类似的函数,可用于转换类型,如str和float。实际上,它们并不是函数,而
是类。类将在本书后面更详细地介绍。

模块math还包含其他几个很有用的函数。例如,ceil与floor相反,返回大于或等于给定数
的最小整数。

>>> math.ceil(32.3) 
33 
>>> math.ceil(32) 
32 

如果确定不会从不同模块导入多个同名函数,你可能不想每次调用函数时都指定模块名。在
这种情况下,可使用命令import的如下变种:

>>> from math import sqrt 
>>> sqrt(9) 
3.0

通过使用命令import的变种from module import function,可在调用函数时不指定模块前缀。

事实上,可使用变量来引用函数(以及其他大部分Python元素)。执行赋值语句foo =
math.sqrt后,就可使用foo来计算平方根。例如,foo(4)的结果为2.0。

1.8.1 cmath 和复数

函数sqrt用于计算平方根。下面来看看向它提供一个负数的情况:

>>> from math import sqrt 
>>> sqrt(-1) 
Traceback (most recent call last): 
... 
ValueError: math domain error

在有些平台上,结果如下:

>>> sqrt(-1) 
nan

nan具有特殊含义,指的是“非数值”(not a number)

如果我们坚持将值域限定为实数,并使用其近似的浮点数实现,就无法计算负数的平方根。
负数的平方根为虚数,而由实部和虚部组成的数为复数。Python标准库提供了一个专门用于处理
复数的模块。

>>> import cmath 
>>> cmath.sqrt(-1) 
1j

注意到这里没有使用from ... import ...。如果使用了这种import命令,将无法使用常规函
数sqrt。类似这样的名称冲突很隐蔽,因此除非必须使用from版的import命令,否则应坚持使用
常规版import命令。
1j是个虚数,虚数都以j(或J)结尾。复数算术运算都基于如下定义:-1的平方根为1j。这
里不深入探讨这个主题,只举一个例子来结束对复数的讨论:

>>> (1 + 3j) * (9 + 4j) 
(-3 + 31j)

从这个示例可知,Python本身提供了对复数的支持。

Python没有专门表示虚数的类型,而将虚数视为实部为零的复数。

1.8.2 回到未来

据说Python之父Guido van Rossum有一台时光机,因为这样的情况出现了多次:大家要求
Python提供某项功能时,却发现这项功能早已实现。当然,并非什么人都能进入这台时光机,不
过Guido很体贴,通过神奇模块__future__让Python具备了时光机的部分功能。对于Python当前不
支持,但未来将成为标准组成部分的功能,你可从这个模块进行导入。这一点你在1.3节已经见
识过,本书后面也将经常遇到这个模块。

1.9 保存并执行程序

首先,你需要一个文本编辑器——最好是专门用于编程的(不推荐使用Microsoft Word之类
的软件,但如果你使用的是这样的软件,务必以纯文本的方式保存代码)。如果你使用的是IDLE,
那就太幸运了。在这种情况下,只需选择菜单File→New File。

1.9.1 从命令提示符运行 Python 脚本

在Windows中使用如下命令来执行这个脚本:
C:>python hello.py
在UNIX系统中,可使用如下命令:
$ python hello.py
如你所见,命令是一样的,只是系统提示符不同。

1.9.2 让脚本像普通程序一样

在有些情况下,你希望能够像执行其他程序(如Web浏览器或文本编辑器)一样执行Python
脚本,而无需显式地使用Python解释器。UNIX提供了实现这种目标的标准方式:让脚本的第一
行以字符序列#!(称为pound bang或shebang)开始,并在它后面指定用于对脚本进行解释的程序
(这里是Python)的绝对路径。即便你对这一点不太明白,只需将下面的代码作为脚本的第一行,
就可在UNIX中轻松运行脚本:

#!/usr/bin/env python

不管Python库位于什么地方,这都将让你能够像运行普通程序一样运行脚本。如果你安装了
多个版本的Python,可用更具体的可执行文件名(如python3)替换python。
要像普通程序一样运行脚本,还必须将其变成可执行的:

$ chmod a+x hello.py

现在,可以像下面这样来运行它(假定当前目录包含在执行路径中):

$ hello.py

如果这不管用,请尝试使用./hello.py,这在当前目录(.)未包含在执行路径中时也管用(负
责的系统管理员会告诉你执行路径是什么)。
如果你愿意,可对文件进行重命名并删除扩展名.py,使其看起来更像普通程序。

如果双击会如何呢
在Windows中,扩展名.py是让脚本像普通程序一样的关键所在。请尝试双击前一节保存的文
件hello.py。

1.9.3 注释

在Python中,井号(#)比较特殊:在代码中,井号后面到行尾的所有内容都将被忽略。(这
也是Python解释器未被前面的/usr/bin/env卡住的原因所在。)

1.10 字符串

1.10.1 单引号字符串以及对引号转义

第二个字符串包含双引号,因此必须使用单引号将整个字符串括起,原因和前面一样。实
际上,并非必须这样做(这样做只是出于方便考虑)。可使用反斜杠(\)对引号进行转义

厌烦了反斜杠?你在本章后面将看到,在大多数情况下,可通过使用长字符串和原始字
符串(可结合使用这两种字符串)来避免使用反斜杠。

1.10.2 拼接字符串

为处理前述不太正常的示例,来看另一种表示这个字符串的方式:

>>> "Let's say " '"Hello, world!"' 
'Let\'s say "Hello, world!"'

我依次输入了两个字符串,而Python自动将它们拼接起来了(合并为一个字符串)。这种机
制用得不多,但有时候很有用。然而,仅当你同时依次输入两个字符串时,这种机制才管用。

>>> x = "Hello, " 
>>> y = "world!" 
>>> x y 
SyntaxError: invalid syntax

换而言之,这是一种输入字符串的特殊方式,而非通用的字符串拼接方法。那么应该如何拼
接字符串呢?就像将数相加一样,将它们相加:

>>> "Hello, " + "world!" 
'Hello, world!' 
>>> x = "Hello, " 
>>> y = "world!" 
>>> x + y 
'Hello, world!'

1.10.3 字符串表示 str 和 repr

Python打印所有的字符串时,都用引号将其括起。你可能通过前面的示例发现了这一点。这
是因为Python打印值时,保留其在代码中的样子,而不是你希望用户看到的样子。但如果你使用
print,结果将不同。

>>> "Hello, world!" 
'Hello, world!' 
>>> print("Hello, world!") 
Hello, world!

如果再加上表示换行符的编码\n,差别将更明显。

>>> "Hello,\nworld!" 
'Hello,\nworld!' 
>>> print("Hello,\nworld!") 
Hello, 
world!

通过两种不同的机制将值转换成了字符串。你可通过使用函数str和repr①直接使用这两种机
制。使用str能以合理的方式将值转换为用户能够看懂的字符串。例如,尽可能将特殊字符编码
转换为相应的字符。然而,使用repr时,通常会获得值的合法Python表达式表示。

repr 是representation及描述的意思,不是对人的描述,而是对python机器的描述

>>> print(repr("Hello,\nworld!")) 
'Hello,\nworld!' 
>>> print(str("Hello,\nworld!")) 
Hello, 
world!

① 实际上,像int一样,str也是一个类,但repr是一个函数

1.10.4 长字符串、原始字符串和字节

有一些独特而有用的字符串表示方式。例如,有一种独特的语法可用于表示包含换行符或反
斜杠的字符串(长字符串和原始字符串)。对于包含特殊符号的字符串,Python 2还提供了一种专
用的表示语法,结果为Unicode字符串。这种语法现在依然管用,但是多余,因为在Python 3中,
所有的字符串都是Unicode字符串。Python 3还引入了一种新语法,用于表示大致相当于老式字符
串的字节对象。你将看到,在处理Unicode编码方面,这种对象依然扮演着重要的角色。

  1. 长字符串
    要表示很长的字符串(跨越多行的字符串),可使用三引号(而不是普通引号)。
print('''This is a very long string. It continues here. 
And it's not over yet. "Hello, world!" 
Still here.''')

还可使用三个双引号,如"""like this"""。请注意,这让解释器能够识别表示字符串开始
和结束位置的引号,因此字符串本身可包含单引号和双引号,无需使用反斜杠进行转义。

  1. 原始字符串
    原始字符串不以特殊方式处理反斜杠,因此在有些情况下很有用②。在常规字符串中,反斜
    杠扮演着特殊角色:它对字符进行转义,让你能够在字符串中包含原本无法包含的字符。例如,
    你已经看到可使用\n表示换行符,从而像下面这样在字符串中包含换行符:
>>> print('Hello,\nworld!') 
Hello, 
world!

这通常挺好,但在有些情况下,并非你想要的结果。如果你要在字符串中包含\n呢?例如,
你可能要在字符串中包含DOS路径C:\nowhere。

>>> path = 'C:\nowhere' 
>>> path 
'C:\nowhere'

这好像没问题,但如果将其打印出来,就会出现问题。

>>> print(path) 
C: 
owhere

这并非你想要的结果,不是吗?那该怎么办呢?可对反斜杠本身进行转义。

>>> print('C:\\nowhere') 
C:\nowhere

这很好,但对于很长的路径,将需要使用大量的反斜杠。
path = 'C:\Program Files\fnord\foo\bar\baz\frozz\bozz'
在这样的情况下,原始字符串可派上用场,因为它们根本不会对反斜杠做特殊处理,而是让
字符串包含的每个字符都保持原样。

>>> print(r'C:\nowhere') 
C:\nowhere 
>>> print(r'C:\Program Files\fnord\foo\bar\baz\frozz\bozz') 
C:\Program Files\fnord\foo\bar\baz\frozz\bozz

如你所见,原始字符串用前缀r表示。看起来可在原始字符串中包含任何字符,这大致是正
确的。一个例外是,引号需要像通常那样进行转义,但这意味着用于执行转义的反斜杠也将包含
在最终的字符串中。

raw:adj. 生的;未加工的;阴冷的;刺痛的;擦掉皮的;无经验的;(在艺术等方面)不成熟的
原始字符串是为正则表达式设计的,也可以用来方便地表示Windows系统下的路径,不过,如果路径以"" 结尾那么会出错。
当反斜杠后跟原始字符串中的引号时,将对其进行转义。 但是,反斜杠也保留在结果中。 由于此功能,我们无法创建单反斜杠的原始字符串。 另外,原始字符串的末尾不能有奇数个反斜杠。

>>> print(r'Let\'s go!') 
Let\'s go!

另外,原始字符串不能以单个反斜杠结尾。换而言之,原始字符串的最后一个字符不能是反
斜杠,除非你对其进行转义(但进行转义时,用于转义的反斜杠也将是字符串的一部分)。根据
前一个示例,这一点应该是显而易见的。如果最后一个字符(位于结束引号前面的那个字符)为
反斜杠,且未对其进行转义,Python将无法判断字符串是否到此结束。

>>> print(r"This is illegal\") 
SyntaxError: EOL while scanning string literal

这合乎情理,但如果要指定以反斜杠结尾的原始字符串(如以反斜杠结尾的DOS路径),该
如何办呢?本节介绍了大量技巧,应该能够帮助你解决这个问题,但基本技巧是将反斜杠单独作
为一个字符串,下面是一个简单的示例:

>>> print(r'C:\Program Files\foo\bar' '\\') 
C:\Program Files\foo\bar\

请注意,指定原始字符串时,可使用单引号或双引号将其括起,还可使用三引号将其括起。

② 编写正则表达式时,原始字符串很有用,这将在第10章详细介绍。

  1. Unicode、bytes和bytearray
    有一种指定Unicode字符的通用
    机制:使用16或32位的十六进制字面量(分别加上前缀\u或\U)或者使用字符的Unicode名称
    (\N{name})。
    为与C语言互操作
    以及将文本写入文件或通过网络套接字发送出去,Python提供了两种类似的类型:不可变的bytes
    和可变的bytearray。如果需要,可直接创建bytes对象(而不是字符串),方法是使用前缀b:
>>> b'Hello, world!' 
b'Hello, world!'

然而,1字节只能表示256个不同的值,离Unicode标准的要求差很远。Python bytes字面量只
支持ASCII标准中的128个字符,而余下的128个值必须用转义序列表示,如\xf0表示十六进制值
0xf0(即240)。

然而,有一种非常巧妙的替代方式:不使用全部32位,而是使用变长编码,即对于不同的字
符,使用不同数量的字节进行编码。这种编码方式主要出自计算机先锋Kenneth Thompson之手。
通过使用这种编码,可节省占用的空间,就像摩尔斯码使用较少的点和短线表示常见的字母,从
而减少工作量一样①。具体地说,进行单字节编码时,依然使用ASCII编码,以便与较旧的系统兼
容;但对于不在这个范围内的字符,使用多个字节(最多为6个)进行编码。下面来使用ASCII、
UTF-8和UTF-32编码将字符串转换为bytes。

>>> "Hello, world!".encode("ASCII") 
b'Hello, world!' 
>>> "Hello, world!".encode("UTF-8") 
b'Hello, world!' 
>>> "Hello, world!".encode("UTF-32") 
b'\xff\xfe\x00\x00H\x00\x00\x00e\x00\x00\x00l\x00\x00\x00l\x00\x00\x00o\x00\x00\x00,\x00\ 
x00\x00 \x00\x00\x00w\x00\x00\x00o\x00\x00\x00r\x00\x00\x00l\x00\x00\x00d\x00\x00\x00!\x00\ 
x00\x00'

可不使用方法encode和decode,而直接创建bytes和str(即字符串)对象,如下所示:

>>> bytes("Hællå, wørld!", encoding="utf-8") 
b'H\xc3\xa6ll\xc3\xa5, w\xc3\xb8rld!' 
>>> str(b'H\xc3\xa6ll\xc3\xa5, w\xc3\xb8rld!', encoding="utf-8") 
'Hællå, wørld!'

源代码也将被编码,且默认使用的也是UTF-8编码。如果你想使用其他编码(例如,如果
你使用的文本编辑器使用其他编码来存储源代码),可使用特殊的注释来指定。

-- coding: encoding name --

请将其中的encoding name替换为你要使用的编码(大小写都行),如utf-8或latin-1。

最后,Python还提供了bytearray,它是bytes的可变版。从某种意义上说,它就像是可修改
的字符串——常规字符串是不能修改的。然而,bytearray其实是为在幕后使用而设计的,因此
作为类字符串使用时对用户并不友好。例如,要替换其中的字符,必须将其指定为0~255的值。
因此,要插入字符,必须使用ord获取其序数值(ordinal value)。

>>> x = bytearray(b"Hello!") 
>>> x[1] = ord(b"u") 
>>> x 
bytearray(b'Hullo!')
posted @ 2021-06-14 11:08  干饭啦  阅读(434)  评论(0编辑  收藏  举报