Python 基础语法

Python 基础语法

必知概念

编码

Python 3.x 相比于 Python 2.7 最大的一个改变就是使用 Unicode 作为默认编码。Pyhton 2.x 中直接写中文会报错,而 Python 3.x 中可以直接写中文了,并且允许使用中文作为变量名(但不推荐)。

因此,如果你看 Python 2.x 的代码,可能经常会遇到文件头有如下声明,用于指定 UTF-8 编码。

# -*- coding:utf-8 -*-

从开源项目看,支持 Python 3.x 的比例已经大大提高,通常知名的项目都会支持 Python 2.7 和 Python 3.x。

标识符和关键字

在 Python 中,标识符由字母数字下划线组成,但不能以数字开头,并且字母是区分大小写的。

值得注意的是,下划线在 Python 标识符中有特殊的意义:

  • 以单下划线开头 _foo 的代表不能直接访问的类属性,需要通过类提供的接口进行访问,不能用 from xxx import * 而导入;
  • 以双下划线开头的 __foo 代表类的私有成员;
  • 以双下划线开头和结尾的 __foo__ 代表 Python 里特殊方法专用的标识,如 __init__() 代表类的构造函数。

Python 的关键字也称为保留字,我们不能用关键字作为标识符名称。那我们怎么知道 Python 里面有哪些关键字呢?

使用 keyword 模块来查看:

>>> import keyword
>>> keyword.kwlist
['False','None','True','and','as','assert',
 'break','class','continue','def','del',
 'elif','else','except','finally','for','from',
 'global','if','import','in','is','lambda',
 'nonlocal','not','or','pass','raise','return',
 'try','while','with','yield']

模块导入机制

关于 “模块导入”,Python 官方给出的解释是这样的:Python code in one module gains access to the code in another module by the process of importing it.

意思就是说:Python 的模块太多啦,总不能把代码都写一块去吧?所以为了便于相互协作和后期维护,我们要把功能封装成模块,然后通过导入模块来复用代码。于是,我们就可以像上面的例子中 import keyword 来导入 keyword 模块,然后就可以访问模块中的函数和变量啦。 

通常,模块有以下几种导入方式:

# 导入一个模块
import module_name

# 导入多个模块
import module_name1, module_name2

# 导入模块中的指定的属性、方法(不加括号)、类
from moudule_name import moudule_element [as new_name]

import 某一模块,相当于在当前环境中把某块内的代码执行一遍,使得该模块定义的变量、方法可见。为防止名称冲突,引用时通过 模块名.变量名(module.variable)的方式访问。如果在当前环境中还有同样名字的变量 variable,它们俩之间是没有任何关系的,引用时要区分开。

import module_name” 的本质是将 ”module_name.py” 中的全部代码加载到内存并==赋值给与模块同名的变量==写在当前文件中,这个变量的类型是 module。

如果代码中有多个地方需要重复调用同一个模块的同一个方法或变量,每次调用时, Python 都需要重复查找模块。所以可以使用 ”from module_name import module_element“ 进行优化,减少了查找的过程。

另外,import 是具有层次性质的,即在当前模块中 import module_name 模块,那么,当前模块是不能访问 module_name 模块中 import 其他模块的对象的!

那么问题来了,模块从哪里导入?又能导入哪些模块呢?

Python 在模块导入的时候,默认先在当前目录下查找,然后再到系统中查找。系统查找的范围是 sys.path 下的所有路径,并且按顺序查找。

>>> import sys
>>> sys.path
['',
 '/usr/lib/python35.zip',
 '/usr/lib/python3.5',
 '/usr/lib/python3.5/plat-x86_64-linux-gnu',
 '/usr/lib/python3.5/lib-dynload',
 '/usr/local/lib/python3.5/dist-packages',
 '/usr/lib/python3/dist-packages']

执行 sys.modules 可以列出 Python 启动时导入的模块,当某个模块第一次导入时,sys.modules 会自动记录该模块,后面再次导入该模块时,则直接查询 sys.modules,从而加快程序运行速度。实际上,sys.modules 是一个全局字典,因此可以使用字典所拥有的一切方法,比如 sys.modules.keys()

模块和包的区别

模块(module):用来从逻辑(实现一个功能)上组织 Python 代码(变量、函数、类),本质就是 *.py 文件。文件是物理上组织方式 ”module_name.py“,模块是逻辑上组织方式 ”module_name“。如果需要引用其他模块内的变量、方法或对象,在模块内还可以 import 进其他模块。

包(package):定义了一个由模块和子包组成的 Python 应用程序执行环境,本质就是一个有层次的文件目录结构(必须带有一个 __init__.py 文件)。

我们可以通过 pip3 freeze 命令可以查看当前 Python 环境中已安装的包。

内建函数和库函数

内建模块(built-in modules)是 Python 解释器实现的模块(C 语言编写),它为 Python 程序直接提供操作接口,包括数据类型、文件 I/O 等常用的函数。如果没有这些 built-in 模块,Python 也将失去意义。实际上,内建函数也属于 Python 标准库的一部分。

内建函数都在 __builtins__ 模块里面,在 Python 程序中,我们可以直接(global)使用它们,通过 “dir(__builtins__)” 可以查看 Python 中的内建函数。

标准库(Standard Library)提供了很多 Python 编写的模块和函数,它们通常都是针对某一个特定的功能而设计的,比如 os、sys、time、datetime、math、urllib 模块等等。如果你使用的是 Windows 平台的 Python 环境,通常已经安装了完整的标准库和很多额外的软件包。不幸的是,如果你和我一样使用类 Unix 系统,那么通常只会安装 Python 解释器珍藏的那部分库,所以你还需要根据实际情况安装更多的软件包。

好消息是,有一个 PyPI(Python Package index)的网站收集了成千上万来自全球各地的 Python 模块。所以,我们推荐使用 pip 工具来安装相应的模块。比如使用如下命令安装 paho-mqtt 包:

pip3 install paho-mqtt

除了内建函数,其他函数(包括标准库和第三方模块)都需要 import 关键字导入模块才能使用。第三方模块一般安装在 dist-packages 或 site-packages 目录下。

数据类型

Python3 中有六个标准的数据类型。

Number 数字

  • Python3 支持 intfloatboolcomplex
  • 在 Python3 中,只有一种整数类型 int,表示为长整型,没有 Python2 中的 Long
  • 像大多数语言一样,数值类型的赋值和计算都是很直观的。
  • 内置的 type() 函数可以用来查询变量所指的对象类型。
>>> a, b, c, d = 20, 5.5, True, 4+3j

>>> print(type(a), type(b), type(c), type(d))
<class 'int'> <class 'float'> <class 'bool'> <class 'complex'>
  • 也可以使用 isinstance() 函数来判断。
>>> isinstance(a, int)                                                     
True

>>> isinstance(a, float)                                                   
False
  • isinstancetype 的区别在于:
    • type() 不会认为子类是一种父类类型;
    • isinstance() 会认为子类是一种父类类型。
class A:
    pass

class B(A):
    pass 

>>> isinstance(A(), A)                                                     
True

>>> type(A()) == A                                                         
True

>>> isinstance(B(), A)                                                     
True

>>> type(B()) == A                                                         
False

Strings 字符串

List 列表

Tuple 元组

Sets 集合

Dictionary 字典

类型转换

类型转换是一种常见任务,Python 提供了很多简化这种工作的内置函数。

显式转换

将整数转换为浮点数

>>> float(3)
3.0

将字符串转换为浮点数

>>> float('3.2')
3.2

将整数转换为字符串

>>> str(85)
'85'

将浮点数转换为字符串

>>> str(-9.78)
'-9.78'

将浮点数转换为整数

这种转换稍微有点麻烦,因为你必须决定如何处理浮点数的小数部分。函数 int(x) 将小数部分删除,而 round(x) 采用标准圆整方式。

>>> int(8.54)
8
>>> round(8.54)
9
>>> round(8.5)
8

圆整策略:四舍六入五成双,这是计算机上圆整数字的标准方式。更多细节请参考 http://en.wikipedia.org/wiki/Rounding

对于大多数应用程序,使用 int(x)float(x)round(x) 就能满足数值转换需求。然而,为处理更具体的转换,Python 模块 math 提供了更多小数部分删除的函数:math.trunc(x)math.ceil(x)math.floor(x)

将字符串转换为数字

这很容易,只需使用函数 int(s)float(s) 即可。

>>> int('5')
5
>>> float('6')
6.0

注意:使用 int(s)float(s) 将字符串转换为整数和浮点数时,是假定字符串看起来像 Python 整数或浮点数,如果不是这样,将出现一条错误消息,指出不能执行转换。比如:

>>> int('10.2')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '10.2'
>>> float('6s')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: could not convert string to float: '6s'

如果用科学记数法表示浮点数的字符串则可以转换:

>>> float('6e-02')
0.06

隐式转换

有时候 Python 会自动在数值类型之间转换,而不要求显式地调用转换函数。比如:

>>> 89 * 1.2
106.8

这里自动将89转换为89.0,再将其与1.2相乘。一般而言,表达式同时包含整数和浮点数时,Python 会自动将整数转换为浮点数。

变量

变量是最重要的编程概念之一。在 Python 中,变量标记(label)或指向一个值。

  • Python 中的变量不需要声明,只需要赋值就可以使用。
  • 在 Python 中,变量就是变量,没有类型(所说的“类型”是变量所指向的内存中对象的类型)。

变量命名规则

变量名必须遵守下面几条基本规则:

  • 变量名的长度不受限制,但其中的字符必须是字母、数字或下划线,不能使用空格、连字符、标点符号、引号或其他字符。
  • 变量名的第一个字符不能是数字,而必须是字母或下划线。
  • Python 区分大小写,因此 TAX、Tax 和 tax 是截然不同的变量名。
  • 不能将 Python 关键字用作变量名。例如 if、else、while、def、or、and、not、in 等等。

与变量一样,函数、模块和类也都有名称。我们将这些名称统称为标识符。

下划线命名模式

单下划线和双下划线在 Python 变量和方法名称中都各有其含义。有一些含义仅仅是依照约定,被视作是对程序员的提示,而有一些含义是由 Python 解释器严格执行的。

这里先简单介绍一下:

模式 举例 含义
单前导下划线 _var 命名约定,仅供内部使用。通常不会由 Python 解释器强制执行(通配符导入除外),只作为对程序员的提示。
单末尾下划线 var_ 按约定使用以避免与 Python 关键字的命名冲突。
双前导下划线 __var 当在类上下文中使用时,触发“名称修饰”。由 Python 解释器强制执行。
双前导和双末尾下划线 __var__ 表示 Python 语言定义的特殊方法。避免在你自己的属性中使用这种命名方案。
单下划线 _ 有时用作临时或无意义(不关心)变量的名称。也表示 Python REPL 中最近一个表达式的结果。

参考阅读:https://blog.csdn.net/tcx1992/article/details/80105645

赋值语句

赋值语句包含3个主要部分:左值、赋值运算符和右值。

赋值语句有两个用途:

  • 定义新的变量;
  • 让已定义的变量指向特定值。

在 Python 中,可以将任何值赋给变量,包括其他变量的值,请看下面的一系列赋值语句:

x = 5
y = 'cat'
x = y

常用于描述变量和值的术语很多。我们有时候说将值赋给变量或给变量指定值。

对于已经赋值的变量,说它指向、标记或拥有相应的值。

程序员有时说变量包含其值,好像变量是桶,而值在桶内。这种说法的问题在于,Python 变量并不符合你以为的 “包含” 模型。例如,在 Python 中,同一个对象不能同时出现在多个桶内,但可以有多个变量同时指向它。

多重赋值

在 Python 中,有一种便利的技巧,让你能够同时给多个变量赋值:

x, y, z = 1, 'two', 3.0

在交互模式下测试

>>> x, y, z = 1, 'two', 3.0
>>> x
1
>>> y
'two'
>>> z
3.0
>>> x, y, z
(1, 'two', 3.0)

正如最后一条语句演示的,还可以在一行显示多个值,方法是将它们作为元组,元组总是以左圆括号开始,以右圆括号结尾。

多重赋值的一个很实用的用途是交换两个变量的值,如下:

a, b = 5, 9  # (5, 9)
a, b = b, a  # (9, 5)

语句 a, b = b, a 的含义是同时给变量 a 和 b 赋值。如果不适用多重赋值,将两个变量的值互换就需要使用中间变量。

多重赋值的功能并不比常规赋值多,它只是一种偶尔使用的比较便利的快捷方式。

变量如何引用值

对于 x = expr 这样的 Python 赋值语句,可以这样解读:让 x 指向表达式 expr 的值。

对于没有任何变量指向的值,Python 会自动将其删除。一般而言,Python 跟踪所有的值,并自动删除不再有变量指向的值。这称为垃圾收集,因此 Python 程序员很少需要为删除值操心。

  • 赋值时不复制
    • 你必须得明白,赋值语句并不会复制指向的值,而只是标记和重新标记既有值。因此,无论变量指向的对象有多大、多复杂,赋值语句的效率都非常高。
  • 数字和字符串是不可变的
    • 在 Python 中,数字和字符串的一个重要特征是不可变,即不能以任何方式修改它们。在看起来是修改数字或字符串的情况下,Python 实际上是在创建修改版本的拷贝。

输入和输出

编码风格

行与缩进

注释

运算符

算术运算符

整数算术

整数是不带小数部分的数字,如 12、-89 和 0。Python 支持4种基本算术运算:+(加)、-(减)、*(乘)、/(除)。Python 还使用 **% 来分别表示乘方和求余,此外还有一个整除运算符 //,其工作原理类似于 /,但结果总是整数(使用去尾法而非四舍五入)。

基本算数运算符

名称 运算符 示例
加法 + 3 + 4 结果为7
减法 - 5 - 3 结果为2
乘法 * 2 * 3 结果为6
除法 / 3 / 2 结果为1.5
整除 // 3 // 2 结果为1
求余 % 25 % 3 结果为1
乘方 ** 3 ** 3 结果为27

上表总结了 Python 的基本算术运算符,并按优先级从低到高的顺序将它们编组。Python 算术运算的规则与常规算术运算相同,可以使用圆括号改变计算顺序。

与其他大多数编程语言不同,Python 对整数的长度没有限制,你可以执行数十位甚至数百位数、千位的整数运算。比如:

>>> 27 **100
136891479058588375991326027382088315966463695625337436471480190078368997177499076593800206155688941388250484440597994042813512732765695774566001

浮点数算术

在 Python 中,浮点数就是带小数点的数字,比如 2.7、-3.14 和 12.88 都是浮点数。所有适用于整数的算术运算都可用于浮点数,包括 %(求余) 和 //(整除)。

>>> 3.8 + -43.2
-39.400000000000006
>>> 12.6 * 0.5
6.3
>>> 12.6 + 0.01
12.61
>>> 365.0 / 12
30.416666666666668
>>> 8.8 ** -5.4
7.939507629591553e-06
>>> 5.6 // 2
2.0
>>> 5.6 % 3.2
2.3999999999999995

需要注意的是,近似误差很常见,因此显示的通常不是准确值。

浮点数字面量

对于非常大或非常小的浮点数,通常用科学记数法(scientific notation)表示。比如上面的 e-06 表示将它前面的数字乘以 10^-6^,如果有需要,也可以直接使用科学记数法。

>>> 2.3e02
230.0

Python 的浮点数在使用小数点方面非常灵活,以下用法都是没问题的:

>>> 3.
3.0
>>> 3.0
3.0
>>> .5
0.5
>>> 0.5
0.5

通常 5.0 比 5. 更清晰,因为后者可能令人迷惑,它看起来像句子结尾。区分 5 和 5.0 很重要,因为前者是整数,后者是浮点数,它们的内部表示大相径庭。

溢出

与整数不同,浮点数存在上限和下限,超出上限或下限将导致溢出错误。溢出错误意味着计算结果太大或太小,Python 无法将其表示为浮点数。比如计算 500 ** 1000 是没问题的,但是换成 500.0 就会溢出:

>>> 500.0 ** 1000
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Numerical result out of range')

面对溢出错误,Python 可能沉默不语,即继续执行错误的计算,而不告诉你出了问题。一般而言,避免溢出错误的职责由程序员承担。

精度有限

无论在哪种计算机上,浮点数的精度都是一个无法解决的难题。在计算机中,数字用二进制(基数为2)表示,但并非所有浮点数都可以用二进制精确地表示。即便在最简单的情况下,也可能出现问题,比如:

>>> 1 - 2 / 3
0.33333333333333337

结果应该是小数点后有无穷个3,但这里只包含17位。另外,最后一位也不对(应该是3而不是7)。

这些细微的误差通常不是问题,对大多数程序来说,小数点后面包含17位足够了。然而,当你执行大量计算时,小误差会累积出大误差。例如,计算新设计的桥梁承受的压力时,必须考虑细微的浮点数误差,避免它们累积出大误差。

==一般而言,应优先考虑使用整数而不是浮点数,因为它们更精确且绝不会溢出。==

比较运算符

赋值运算符

逻辑运算符

位运算符

成员运算符

身份运算符

运算符优先级

流程控制

前面编写的程序都是顺序执行的,没有分支,也不会返回到以前的语句。在实际应用中,我们通常会使用 if 语句和循环来改变语句的执行顺序。

分支结构

循环结构

Leave a Reply