Python详细介绍及使用(基础篇)

第一章 Python基础

    Python的由来:1989年,为了打发圣诞节假期,Guido开始写Python语言的编译/解释器。Python来自Guido所挚爱的电视剧Monty Python's Flying Circus (BBC1960-1970年代播放的室内情景幽默剧,以当时的英国生活为素材)。他希望这个新的叫做Python的语言,能实现他的理念(一种C和shell之间,功能全面,易学易用,可拓展的语言)。

    1991年,第一个Python编译器(同时也是解释器)诞生。它是用C语言实现的,并能够调用C库(.so文件)。从一出生,Python已经具有了:类(class),函数(function),异常处理(exception),包括表(list)和词典(dictionary)在内的核心数据类型,以及模块(module)为基础的拓展系统。

    Python语法很多来自C,但又受到ABC语言的强烈影响。(ABC语言旨在替代BASIC,Pascal等语言-Python创始人Guido van Rossum于20世纪80年代曾在ABC系统开发中工作了数年)今天Python已经进入到3.0的时代。由于Python 3.0向后不兼容,所以从2.0到3.0的过渡并不容易。另一方面,有人说Python的运算性能低于C++和Java,Python的性能依然值得改进。

一、Python基本概念及环境配置

1、基本概念

    Python是一种解释型语言,边执行边编译。但是这样会影响执行效率,通常编译型语言的效率比解释型语言高。不过解释型语言对平台的依赖性更低。

    Python优势:代码量少、可移植性、有丰富的库。胶水语言,可以将python和非python所编写出来的库,让python进行调用。

    python诞生于1989年。Python开发的网站:知乎,拉钩,果壳,豆瓣,youtobe......

    Python语言设计的哲学:优雅、明确(尽量使用一种方式做一件事)、简单

    Python可设计的领域:系统编程、GUI、网络编程(爬虫...)、Web编程、数据库编程...

    Python运行时都需要生产字节码文件,交由虚拟机来处理。当我们在运行python文件程序的时候,python解释器将源码转换为字节码,然后由解释器来执行这些字节码,以求重复执行时更快更高效。不像java那样要先编译才能再执行,python可以边执行边编译。[java比较特殊,java这个编译过程并不是直接编译成机器语言,而是将其编译成字节码文件,由JVM将字节码文件翻译成机器语言,由此很好的实现了跨平台的特性]

    注:解释性语言是指他们都有自己的解释器,也可以通俗的理解为翻译器(计算机本身是不能直接理解高级语言的,只能直接理解机器语言,所以必须把高级语言翻译成机器语言),解释性语言对平台的依赖相对较小,但是在执行过程中要比编译性语言的效率低。

    编译型语言:在程序执行前,有一个单独的编译过程,将程序直接翻译成机器语言。以后执行这个程序的时候就不需要再进行翻译了。

    Python 2.7 是 2.x 系列中的最后一个主版本,于2010年7月3日发布。因为Python 维护人员已将新功能开发工作的重点转移到了 Python 3.x 系列中。这意味着,尽管 Python 2 会继续修复bug并更新,以便在新的硬件和支持操作系统版本上正确构建,但不会有新的功能发布。Python 3.0实现了很多非常有用的功能,并打破了向后兼容性。

2、环境变量配置

    安装完成后(如果安装时未添加环境变量),要进行环境变量配置[是为了在任何目录下都可以执行python命令]

    a)进入计算机-属性-高级系统设置-高级-环境变量

    b)找到Path变量,再最后面加入Python的安装路径。

   

    c)win+R 输入cmd,在DOS下输入python,回车出现如图所示,则说明环境变量配置好了

   

二、运行python

1、命令行上的交互式解释器

1.1、交互式解释器

    a)直接启动python(command line)

    b)可以使用DOS启动(运行cmd,使用python启用)

    但是这种交互式模式下,执行完成后很难再次运行。因此保存为.py程序。

1.2、python 命令运行脚本   

    使用命令运行【xxx.py】程序。python  xxx.py

1.3、在编写成.py文件时要注意的问题

    在python3.x中的默认编码为【utf-8】,而在Python2.x中,默认编码为ASCII,如果没有声明,文件中又包含非ASCII编码的字符(如:中文),解析文件的时候就会报错(Non-ASCII character)

    如果是python2.x我们需要运行.py命令,在创建文件时,我们需要在头部文件中声明编码格式。为什么要声明字符编码格式?如果没有此文件的字符编码类型的声明,则按照默认编码去处理。

    在头部声明编码格式(一般在第一行或第二行,#coding = utf-8告诉python解释器按照utf-8读取源代码):

   方式一:

       #coding=<encoding name>    例如:#coding = utf-8   只能放在首行

   方式二:

        #!/user/bin/python

        #-*-coding<encoding name>-*- 例如:# -*- coding: utf-8 -*-

   方式三:

        #!/user/bin/python

        #vim:set fileencoding=<encoding name>  例如:#vim:set fileencoding=utf-8

说明:#!/user/bin/python(#解释:这句话是表明在unix/linux下执行脚本时,要启动的解释器,是/usr/bin下面的python解释器)具体的后面说明。

2、如何生成.pyc/.pyo字节码文件

    前面说到python是解释型语言,但是我们再执行的时候并没有看到有生成字节码文件呀?

python虚拟机执行过程:

    a)完成模块的加载和链接

    b)由编译器(Complier)将源代码翻译为PyCodeObject对象(也就是字节码.pyc/.pyo),并将其写入内存当中

    c)从上诉内存当中(方便CPU的读取)读取指令,并执行

    d)程序结束后,根据命令行调用情况(取决于程序的方式),决定是否将PyCodeObject写会硬盘当中

    e)后续再执行此脚本的时候,会先检查本地是否有上诉字节码文件,若有则执行,否则重复上述步骤。

    为什么不直接生产这些文件?其实虚拟机也是讲究效率的,对于较大的项目如果要将PyCodeObject写会硬盘中,不可避免的要花些时间,而且我们也不知道这个程序是不是只执行一次。

    Python虚拟机(PVM)种类

    a)CPython:原始、标准的实现。平时用的就是Cpython。可以调用C实现的类库,虽然Jpython,IronPython也可以。但是Cpython调用java实现的类库就会麻烦一些

    b)Jython:用于与java语言集成的实现。可以直接调用外部的java类库

    c)IronPython:用于与.NET框架集成的实现。

    直接执行py文件不会自动生成字节码文件,需要手动编译一下:

python [options] [args]

python 命令选项说明

-d    提供调试输出

-O    生产优化的字节码(.pyo文件)

-S    不导入site模块以在启动时查找Python路径

-v    冗余输出(导入语句详细追踪)

-m  mod   将一个模块以脚本形式运行(相当于脚本中的import)

-Q  opt   除法选项

-c  cmd   运行以命令字符串形式提交的Python脚本

file      从给定的文件运行Python脚本

2.1、方式一:命令方式

#语法:

# 单个文件
python -m py_compile xxx.py  

# 批量(目录)
python -m compileall /../path

    1)使用[py_compile模块]生成.pyc字节码文件

          

    2)生成优化的字节码文件[.opt-1.pyc/.opt-2.pyc/.pyo]

         

    3)也可以整个目录一起生成字节码文件[compileall模块]

   

    注:__pycache__目录下不同版本的模块可以共存。python的编译可以有两层优化,-O和-OO,都是编译出.pyo文件,但从文件后缀上,看不出使用的是哪一层优化。这会导致一些使用上的问题。

    因此,从python3.5开始,__pycache__目录下,就不会再有.pyo文件了。PEP 488提出的新的方案,还是回到.pyc文件,使用opt-1和opt-2来区分优化层级。       

2.2、方式二:脚本方式

# 语法
import py_compile
>>> if __name__=='__main__':
	py_compile.compile('c:\hello.py')

>>> import compileall
>>> if __name__=='__main__':
	compileall.compile_dir('C:\\hello\\')

  在交互式解释器上运行(安装好Python后,会有一个IDLE)

  

  python的集成开发环境有很多,比如: PythonWin、PyCharm、Komodo Edit等等

三、Python基础知识

1、基础知识概述

    Python程序可以分解成包、模块、语句、表达式以及对象。

       a)程序由包/模块/函数组成(包是由一系列模块组成)

       b)模块包含语句

       c)语句包含表达式

       d)表达式建立并处理对象

    Python中的内置对象包括:数值类、字符串、列表、字典、元组、文件、集合、编程单元类型(函数、模块、类)等。

    注:包必须包含至少一个__init__.py该文件的内容可以为空。__init__.py用于标识当前文件夹是一个包。例如:lib目录中的xml包。

1.1、Python语句中的基本规则和特殊字符

    在Python中,代码块通过缩进对齐表达式,而不是使用{}来对齐,因为已经没有额外的字符来对齐表达式了,一般缩进4个字符。

特殊符号

说明

#(井号)

注释。可以从一行的任何地方开始。

\(反斜杠)

表示续行。

;(分号)

同一行放多个语句,用分号隔开。

:(冒号)

将代码块的头和体分开。

续行

>>> x=0

>>> if \     #注:续行

    x<3:

       print'True'

>>> x=0

>>> if x<3:   #注:等效方式

   print 'True'

 

1.2、Python中的标识符

   

    注:常量通常定义于模块级别并且所有的字母都是大写,单词用下划线分开。例如MAX_OVERFLOW和TOTAL。 

1.3、关键字

Python KeyWords

and

as

assert

break

class

continue

def

del

elif

else

except

exec

finally

for

from

global

if

import

in

is

lambda

not

or

pass

print

raise

return

try

while

with

yield

None

 

 

 

1.4、变量赋值

    Python是动态类型语言,也就是说不需要预先声明变量的类型。变量的类型在赋值那一刻被初始化。Java是静态类型语言,适用前需声明变量类型。[变量名没有类型,对象才有,即类型是属于对象的,而不是变量]

>>> aInt = 1  #注:不需要预先声明变量的类型
>>> name = '字符串'
>>> del aInt
>>> aInt  #注:删除数值类型对象,删除后无法使用,再次输出会报错
Traceback (most recent call last):
  File "<pyshell#15>", line 1, in <module>
    aInt
NameError: name 'aInt' is not defined

   注:在交互式模式下,变量名“_”用于保存最后输出的表达式的结果

>>> a=1
>>> a
1
>>> _
1
>>> b=3
>>> b
3
>>> _
3
>>> 

1.4、运算符或操作符

运算符优先级

运算符

0、定义/操作符

(...),[...],{...}  索引切片  点操作符

1、乘方

**       注:**表示乘方运算符

2、单目运算符

+(正) -(负)~(取反)  

3、乘/除/取余

*, /, //,%  注://返回数字序列中比真正的商小的最接近的数值

4、加/减

+ , -

5、按位移

<< , >>  向左,向右按位移

6、按位与

&

7、按位异或、或

^ , |

8、关系比较

<, <= ,>,>= ,== ,!=,<>

9、身份成员操作

is ,is not    in,not in

6、逻辑运算符

and  ,   or    ,  not

操作符说明

  1. 身份操作符:is :判定左端对象引用是否等同于右端对象的引用。
  2. 比较操作符:< , >,<=,>=,!=,==
  3. 成员操作符:in , not in    (测试成员关系)
  4. 逻辑运算符:and ,or ,not

type:用于返回对象的类型,对象的类型本身也是一个对象,称为对象的类。

==:比较值是否相同。与java中有区别。

其他操作符

索引:x[i]     切片:x[i:j],x[i:j:stride]

元组:(...)     序列:[...]           字典:{...}

注:运算符 /  和  // 的区别

>>> print(3.2/1)
3.2
>>> print(3.2//1)  #注:返回真正的比商小的最接近的数值
3.0
>>> print(3.8//1)  #注:返回真正的比商小的最接近的数值
3.0
>>> 

1.5、输入/输出

   Python 的 print 语句,与字符串格式运算符( % )结合使用,可实现字符串替换功能,这点和 C 语言中的 printf()函数非常相似。在python3.x中print语句变更为print(...)函数

>>> print "%s is number %d!" % ("Python", 1)  #2.7版本

Python is number 1!

>>> print("%s is number %d" %("Python",1))    #3.8版本

Python is number 1

    注:%s 表示由一个字符串来替换,而%d 表示由一个整数来替换,另外一个很常用的就是%f, 它表示由一个浮点数来替换。

    Python解释器提供了3种标准的文件对象,分别是标准输入、标准输出和标准错误,他们分别在sys模块中分别以sys.stdin、sys.stdout和sys.stderr形式提供。

    注:在2.x版本中实质上print语句只是sys.stdout.write()的简单接口,再加上了一些默认的格式设置。

1.5.1、使用内建函数输入:input()

    在 Python3.x 中 raw_input() 和 input() 进行了整合,去除了python2.x中的raw_input( ),仅保留了input( )函数,其接收任意任性输入,将所有输入默认为字符串处理,并返回字符串类型。

>>> user = input('Enter login name:') #注:所有的输入都被当做字符串返回
Enter login name:username
>>> print(user)
username
>>> 

我们可以使用:help(input) --- 查看input使用说明:

>>> help(input)
Help on built-in function input in module builtins:

input(prompt=None, /)
    Read a string from standard input.  The trailing newline is stripped.
    
    The prompt string, if given, is printed to standard output without a
    trailing newline before reading input.
    
    If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
    On *nix systems, readline is used if available.

大致翻译意思:从标准输入读取字符串。后面的换行符被剥离,以换行作为输入结束的标志的。

2、Python对象

2.1、基本概念

    在Python中,可以说一切皆对象。所有的python对象都拥有三个特性:身份、类型和值。

    1)身份:每一个对象都有一个唯一的身份标识自己,可以使用内建函数id()来得到,这个值可以被认为是内存地址。

    2)类型:每个对象的类型决定了该对象可以保持什么类型的值,可以进行什么样的操作,可以使用内建函数type()查看对象的类型。任何对象都是由类实例化而来的,所以type()返回的是对象,而不是简单的字符串。

    3)值:对象表示的数据项。

例如:

>>> name='jerry'
>>> id(name)
49245552
>>> type(name)
<class 'str'>
>>> name
'jerry'

解释:49245552是对象的身份(内存中的地址)<class 'str'>是对象的类型  'jerry'是对象的值

2.2、对象比较

    a)身份比较:使用is操作符

    b)类型比较:使用type()函数

    c)值比较:使用==操作符

>>> a=123
>>> b=123
>>> a is b  #注:等价于等价于id(a)=id(b)
True
>>> print(id(a),id(b))
8791550600672 8791550600672
>>> type(a) is type(b)
True
>>> a==b
True

3、python中的数据类型

3.1、基本数据类型

   注:python3.x中整型是没有限制大小的,可以当作 long 类型使用,所以 Python3.x 没有 Python2.x 的 long 类型。[列表,字典是可变类型]   [数值类型,字符串,元组是不可变类型]

3.2、其他内建类型

类型分类类型名称描述
可调用types.BuiltinFunctionType内置函数或方法
可调用type内置类型和类的类型
可调用object所有类型和类的祖先
可调用types.FunctionType用户定义的函数
可调用types.MethodType类方法
模块types.ModuleType模块
object所有类型和类的祖先
类型type

内置类型和类的类型

NoneType(None)空对象None
。。。。。。。。。

注:什么是Null对象,什么是(type)类型

   >>> type(42)

   <type 'int'>     #注:42是一个int型对象

   >>> type(type(42))

   <type 'type'>    #注:2.x中类型的对象就是type

   >>> type(type(42)) #注:3.x中

   <class 'type'>

   >>> type(None)

   <type 'NoneType'>

解释:None 是Python 特殊的数据类型NoneType,它是一个空值可将None 赋值给任何数据类型,但不能创建其他NoneType对象。

python2.x中所有类型对象的类型都是type。它也是所有python类型的根和所有python标准类的默认元类。就像java中所有对象的根对象是Object一样。而在python3.x中统一了类(class)和类型(type),使得整体结构更为清晰,更容易理解,更接近于class的面相对象的思想。

# 在 Python 2.x,你得显式写出自定义的类继承于object:
class C(object):
    pass

# 在 Python 3.x,不用显式写出object,如果你不写,则自动继承于object:
class C:
    pass

     object是任何类的基类,任何类(如str,list,tuple,dict等内置数据结构以及自定义的类)在创建时都继承自object类,在Python3.x以后的版本中,可以不用手写继承object,会有系统自动添加继承自object类。object同时也是type的实例,type的基类是object。

    Python3.x除了在object中新增了一些方法,还有一个区别就是:Python 3.x中默认都是新式类,经典类被移除,没必要显式的继承object,Python 2.x中默认都是经典类,只有显式继承了object才是新式类

    新式类:采用算法是广度优先搜索,经典类:采用算法是深度优先搜索

    广度优先(D-B-C-A),是先找距离D最近的从左到右没找到则会继续往上一层找,而深度优先(D-B-A-C),是先找完B在找C。

第二章 基本数据类型

一、数值类型

1、数值类型概述

   数值类型是不可变类型,包括以下几种:

   1)整数类型:int(有符号整数)  例如:(正数)84   (负数)-237  (16进制)0x80 

   长整型:   long(长整型)  例如:-8888888l   0xDCDCDCFDDFL

       注:2.3版本后L可有可无,不会溢出,3.x中已经没有该类型了

    2)布尔值:bool(布尔值)  例如:True = 1  False = 0    注:首字母是大写

    3)浮点型:float(浮点值)  例如:3.14159  4.2E-10

    注:4.2E-10 表示4.2*10的10次方(E也可小写)

    4)复数: complex(复数) 例如:6.23+1.5j

    注:6.23是复数的实部 1.5是复数的虚部 j是虚数单位

    解释:不可变类型:Python中和javascript一样,一切皆对象。对于不可变类型,我们对其任何的修改都会重新创建一个新的对象。Python和java特性很接近,各种内存对象,在不被引用时,会自动的由垃圾收集器回收。[当一个内存对象的引用计数为0时,就会在适合的时机被回收]

扩展:python中的bool值

    Python中的bool的值:True和False。目前来说True和False还不是关键字。python中真假的含义: 

   a)非零数为真,否则为假(0是假)

   b)非空对象为真,否则为假(对象在本质上不是真就是假)

   c)None始终为假。

例如:

>>> class C:pass

>>> c = C()
>>> bool(c)
True

python中,and和or运算符返回真或假的对象,而不是True或False。

   and   两者为真返回后者,两者为假返回前者,一真一假返回假 

   or    两者为假返回后者,两者为真返回前者,一真一假返回真

   not: 返回 True或False

例如:  

>>> d1={}    #空对象,真假性-为假

>>> d2={'a':1} #非空对象,真假性-为真

>>> d3={'b':2}#非空对象,真假性-为真

>>> d4=d2 and d3#两者为真,返回后者d4={‘b’:2},两者为假返回前者

>>> d4=d1 and d2  #一真一假,返回假d4={}

注:and和or本质是短路操作符,and遇到假短路,or遇到真短路后面不再判断

2、数值类型的工厂函数

类(工厂函数)

描述

bool(obj)

返回obj对象的布尔值

int(obj [,base=10])

返回一个字符串/数值对象的整数表示

float(obj)

返回一个字符串或数值对象的浮点数表示

Complex(str)

/complex(real,image=0.0)

返回一个字符串的复数表示或根据给定的实数生成一个复数对象

例如:

>>> int(4.22)

4

>>> long(4) #注:python3.x版本中已经去掉了该类型,统一使用int

4L

>>> float('4')

4.0

>>> complex(4)

(4+0j)

>>> complex(2,3)

(2+3j)

2.1、扩展-工厂函数和内置函数的区别

    Python一切事物都是对象,对象基于类创建。Python 2.2 统一了类型和类,以前的内建转换函数,现在都成了工厂函数。类型工厂函数:看上去像函数,实质上他们是类。调用他们的时候,实际上生成了该类型的一个实例。他不是通过类而是通过函数来创建对象。

    熟悉的工厂函数,(以前版本里的这些叫内建函数):int(),long(),float(),complex(),str(),unicode(),basestring(),list(),tuple(),type()

    后来添加的工厂函数:dict(),bool(),set(),frozenset(),object(),classmethod(),staticmethod(),super(),property()...等等

我们找到源码:bltinmodule.c

#源码:bltinmodule.c  -- Python-2.0.1
static PyMethodDef builtin_methods[] = {
...
    {"int",		builtin_int, 1, int_doc},
	{"isinstance",  builtin_isinstance, 1, isinstance_doc},
	{"issubclass",  builtin_issubclass, 1, issubclass_doc},
	{"len",		builtin_len, 1, len_doc},
	{"list",	builtin_list, 1, list_doc},
	{"locals",	builtin_locals, 1, locals_doc},
	{"long",	builtin_long, 1, long_doc},
...
}

#源码:bltinmodule.c  -- Python-3.8.5
PyObject *
_PyBuiltin_Init(void)
{
...
    SETBUILTIN("None",                  Py_None);
    SETBUILTIN("Ellipsis",              Py_Ellipsis);
    SETBUILTIN("NotImplemented",        Py_NotImplemented);
    SETBUILTIN("False",                 Py_False);
    SETBUILTIN("True",                  Py_True);
    SETBUILTIN("bool",                  &PyBool_Type);
    SETBUILTIN("memoryview",        &PyMemoryView_Type);
    SETBUILTIN("bytearray",             &PyByteArray_Type);
    SETBUILTIN("bytes",                 &PyBytes_Type);
    SETBUILTIN("classmethod",           &PyClassMethod_Type);
    SETBUILTIN("complex",               &PyComplex_Type);
    SETBUILTIN("dict",                  &PyDict_Type);
    SETBUILTIN("enumerate",             &PyEnum_Type);
    SETBUILTIN("filter",                &PyFilter_Type);
    SETBUILTIN("float",                 &PyFloat_Type);
    SETBUILTIN("frozenset",             &PyFrozenSet_Type);
    SETBUILTIN("property",              &PyProperty_Type);
    SETBUILTIN("int",                   &PyLong_Type);
    SETBUILTIN("list",                  &PyList_Type);
    SETBUILTIN("map",                   &PyMap_Type);
    SETBUILTIN("object",                &PyBaseObject_Type);
    SETBUILTIN("range",                 &PyRange_Type);
    SETBUILTIN("reversed",              &PyReversed_Type);
    SETBUILTIN("set",                   &PySet_Type);
    SETBUILTIN("slice",                 &PySlice_Type);
    SETBUILTIN("staticmethod",          &PyStaticMethod_Type);
    SETBUILTIN("str",                   &PyUnicode_Type);
    SETBUILTIN("super",                 &PySuper_Type);
    SETBUILTIN("tuple",                 &PyTuple_Type);
    SETBUILTIN("type",                  &PyType_Type);
    SETBUILTIN("zip",                   &PyZip_Type);
...
}


    内建函数:内建函数也叫内置函数,不需要导入任何包/模块就能直接使用的函数。而工厂函数,简单的理解就是被重新封装的类型,通过工厂函数来创建类的实例化。例如:

>>> age = int(-19)
>>> age
-19
>>> age.__abs__()
19
>>> dir(age)
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
>>> 

    说明: 使用int()工厂函数创建一个数字对象age,这个对象拥有int对象的很多方法,我们用dir(age)将其方法输出,调用对象的__abs__(),输出19.这就是工厂函数。

3、其他常用内建函数

函数

功能

abs(num)

返回num的绝对值

coerce(num1,num2)

将num1和num2转换为同一类型,然后以元组的形式返回

divmod(num1,num2)

除法-取余运算的结合。返回一个元组(num1/num2,num1%num2)

pow(num1,num2[,mod=1])

取num1的num2次方,如果提供了mod参数,则计算结果再对mod进行取余运算

Round(num [,ndig=0])

接受一个浮点数flt并对其四舍五入,保存ndig位小数。若不提供ndig参数,则默认小数点后0位

仅适用于整数的函数

hex(num)

将数字转换成十六进制数,并以字符串形式返回

oct(num)

将数字转换成八进制数,并以字符串形式返回

chr(num)

将ASCII值得数字转换成ASCII字符,范围0<=num<=255

ord(num)

接受一个ASCII/Unicode字符,返回相应的ASCII/Unicode值

unichr(num)

接受Unicode码值,返回对应的Unicode字符

例如:

>>> hex(2)
'0x2'
>>> oct(10)
'0o12'
>>> chr(65)
'A'
>>> ord('A')
65
>>> ord(u'黄') #注:只能传长度为1的字符串
40644
>>> 

二、序列类型--字符串

1、序列概述

   程序的组成:指令+代码   或者   数据结构+算法,Python的最基本的数据结构是序列。

   成员有序排列的,并且可以通过下标偏移量访问到它的一个或者几个成员,这类 Python 类型统称为序列,包括下面这些:字符串,列表,和元组类型

   序列特性:

   a)序列类型中的每一个元素都可以通过指定一个偏移量的方式得到。从左自右下表偏移量从0开始,从右自左从-1开始。

   b)所有的序列都支持迭代。

1.1、序列类型操作符

序列公共操作和方法

描述

seq[i]

返回一个索引为i的序列元素

seq[i:j]

返回一个切片

seq[i:j:stride]

返回一个扩展切片,起始:结束:步长

seq1+seq2

+号合并两个序列,返回新的序列,序列类型要一致

seq*n/n*seq

把序列重复n次,返回新的序列

in/not in seq

成员关系判断。用法:obj in /not in seq   #序列中是否包含obj

for x in s:

迭代

v1,v2,v3=s

变量序列解包,将序列中存储的值指派给各个标识符

1.2、序列的切片

    序列的切片操作可分为:进步切片、多维切片及省略切片

    进步切片语法:Sequence[起始索引:结束索引:步长值]       注:步长不能是0,步长不写默认为1,步长是正表示从左向右,步长是负数从右向左取

    多维切片语法:Sequence[start1:end1,start2:end2]     多维:n=[[[0]*3 for x in range(3) ] for x in range(3)]

    省略切片语法:Sequence[...,start1:end1]  

例如:

>>> str1='012345678'
>>> str1[0:6:1]
'012345'
>>> str1[0:6:2]
'024'
>>> str2='abcdefg'
>>> str2[::-1]
'gfedcba'
>>> str2[-1:-2:-1]
'g'
>>> str3='abc'
>>> str3*2
'abcabc'
>>> t=(1,2,3)
>>> t1,t2,t3=t  #变量序列解包
>>> print(t1,t2,t3)
1 2 3

1.3、序列类型常用内置函数

    python中也有不少内置函数可以对序列进行操作,常用的如下:

函数

功能

enumerate(iter)

接受一个可迭代对象作为参数,返回一个enumerate对象(也是一个迭代器),该对象生成由iter每个元素的index值和item值组成的元组

lens(s)

返回s中元素的个数

min(s [, key=func])

s中的最小值

max(s [, key=func])

s中的最大值

sum(s [,initial])

s中的各项的和(适用于数字序列)

all(s)

检查s中的所有项是否为True

any(s)

检查s中的任意项是否为True

reversed(s)

接受一个序列作为参数,返回一个以逆序访问的迭代器

zip([it0,it1,...itN],[x1,...xn]...)

返回一个列表,其第一个元素是it0,it1,...这些元素的第一个元素组成的元组

例如:

>>> str1='abcdef'
>>> len(str1)
6
>>> max(str1)
'f'
>>> list(zip([1,2,3],['a','b','c']))
[(1, 'a'), (2, 'b'), (3, 'c')]

2、序列-字符串简介

    Python 中字符串被定义为引号(单引号、双引号或三引号)之间的字符集合。字符串是不可变类型,改变一个字符串的元素需要创建一个新的字符串。Python 支持使用成对的单引号、双引号或三引号(三个连续的单引号或者双引号)来包含特殊字符。

   在python2.x中,普通字符串是以8位ASCII码进行存储的,而Unicode字符串则存储为16位Unicode编码字符串,这样能够表示更多的字符集,使用语法是在字符串前面加上前缀u。例如:

    解释:

    方式一声明:str字符串本质上是一个字节流。是原字符经过编码之后的一个个字节,但是并不存储真正的编码方式。[在python2.x中str1存放的你好是文件存储时的编码格式编码后的字节序列。因为在IDLE中默认的编码是GBK,所以你好经过编码之后就是'\xc4\xe3\xba\xc3’,而一般在.py文件中,就是我们存储的文件编码格式。]

    方式二:声明Unicode字符串本质上是一个Unicode对象,内部使用了特定的编码。事实上python中并没有Unicode字符串,只是为了方便,才说Unicode字符串。实际上都是指Unicode对象

    str1的len表示这个字节流共有多少个字节。Str字节长度是11。[在没有设置系统编码时,默认的系统编码是GBK,GBK是双字节编码,一个中文占两个字节,所以你好字节长度为4,加上其他的就是11了]。而str2的len表示这个字符串真正的长度。

   Python3.x中对文本和二进制数据做了更为清晰的区分。python3中改善了复杂的字符编码处理。Python3.x中有两种表示字符序列的类型:bytes和str。前者包含原始的8位值,后者实际包含unicode字符串。即:所有的字符串都是Unicode字符串,由str表示,二进制数据则由bytes表示。

3、字符串的特殊表示

3.1、常见的转义字符

       为了避免字符的特殊意义,设计了一种屏蔽其功能的一个符号--转义字符。

符号

说明

\b

退格

\t

横向制表符

\n

换行

\f

换页

\r

回车

\”

双引号

\’

单引号

\\

反斜杠

3.2、原生字符串操作符

     如果一个字符串包含很多需要转义的字符,对每一个字符都进行转义会很麻烦。为了避免这种情况,我们可以在字符串前面加个前缀 r/R ,表示这是一个 raw (原生)字符串,里面的字符就不需要转义了,但是原生字符串不能表示多行。例如:

语法格式:

    r’(字符串)’   //不能再包含 ’ ,不能表示多行。如:r’abc’ ’ --SyntaxError语法错误

或者:

    r”(字符串)”  //不能包含 ” 不能表示多行

原生字符串用处:

>>> f=open('C:\test.txt','r')
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    f=open('C:\test.txt','r')
OSError: [Errno 22] Invalid argument: 'C:\test.txt'
>>> f=open(r'C:\test.txt','r')
>>> 

    直接使用 文件路径C:\test.txt因为有字符\t,被当做特殊字符,使用原生字符,则为纯粹的路径。则不会报错。

3.3、三引号字符串

   如果需要包含很多特殊字符或者表示多行,过多的使用转义字符就不是那么方便了。三引号就是为了解决这样的问题。语法一对连续的三个单引号或三个双引号。

>>> print('你好:\npython')
你好:
python
>>> print ('''你好: #使用三引号
python''')
你好: #使用三引号
python
>>>

4、字符串操作

4.1、支持序列操作  

>>> str1='abc'

>>> str2='abd'

>>> str1<str2

True

>>> str1[:]

'abc'

>>> str2[1:]

'bd'

注:str按照ASCII值的小大从左自右递归比较的。

4.2、只适用于字符串的操作符

格式化字符

转换方式

%c

转换成字符(ASCII 码值,或者长度为一的字符串)

%r

优先用 repr()函数进行字符串转换

%s

优先用 str()函数进行字符串转换

%d / %i

转成有符号十进制数

%u

转成无符号十进制数

%o

转成无符号八进制数

%x/%X

(Unsigned)转成无符号十六进制数(x/X 代表转换后的十六进制字符的大小写)

%e/%E

转成科学计数法(e/E 控制输出 e/E)

%f/%F

转成浮点数(小数部分自然截断)

%g/%G

%e和%f  /  %E和%F 的简写

%%

输出%

格式化操作符辅助命令:       

符号

作用

*

定义宽度或者小数点精度

-

用做左对齐

+

在正数前面显示加号( + )

<sp>

在正数前面显示空格

#

在八进制数前面显示零('0'),在 十六进制前面显示'0x'或者用的是'x'还是'X')

0

显示的数字前面填充‘0’而不是默认的空格

%

 '%%'输出一个单一的'%'

(var)

映射变量(字典参数)

m.n

m 是显示的最小总宽度,n 是小数点后的位数(如果可用的话)

# 语法描述

%号的用法:%[name][flag][width][.precision]typecode

[]表示可选修饰符

[name]:位于括号中一个属于后面的字典的键名,用于选出一个具体项

[flag]:标志中的一个或多个:

     -:表示左对齐,默认右对齐

     +:表示包含数字符号,正数也会带正号

     0:表示以0填充

[width]:指定小数的宽度

[.precision]:一个小数点,用于按照精度分割字段的宽度,一个数字指定要打印字符串中的最大字符个数,浮点数中小数点后的位数,或者整数的最小位数:
>>> dic={'x':32,'y':27.490325,'z':65}

>>> print('%(x)-10d %(y)0.3f %(z).3f' %dic) #注:x左对齐最小宽度10y最小宽度0小数点精确到三位

32         27.490 65.000

>>> '%#X' % 108  #注:将108转换成无符号的16进制,前面显示0X

'0X6C'

>>> "%x %s %d" %(108,"abc",3)

'6c abc 3'        

>>> '%.2f' % 1234.567890  #注:显示小数点后两位数

'1234.57'

>>> "MM/DD/YY = %02d/%02d/%d" % (1, 18, 17)

'MM/DD/YY = 01/18/17'

注:说明--02d 表示此位填充的是十进制的整数,且为两位,若只有一位则前面添0。

5、字符串内建函数

常用方法

描述

s.captitalize()

首字符变大写

s.center(width)

返回一个字符串居中,并使用空格填充值长度width

s.count(str[,star,end])

指定范围内str出现的次数

s.decode([encoding[,errors])

以encoding指定的编码格式解码str,如果出错默认报ValueError异常,除非error指定的是’ignore’或者’replace’

s.encode([encoding[,errors])

以encoding指定的编码格式编码str,如果出错默认报ValueError异常,除非error指定的是’ignore’或者’replace’

s.endwith(suffix[, start[, end])

检查字符串是否已suffix后缀结尾,返回bool类型

s.find(sub [,start [,end]])

检测sub是否包含在字符串中,如果是返回开始的索引,如果不是则返回-1

s.index(sub [,start[,end]])

找到指定字符串sub首次出现的位置,否则报错

S.isdigit()

字符串中值包含数字则返回True,否则返回False

s.join(t)

将s作为分隔符,连接序列t中的字符串

s.lower()

转换为小写形式

S.replace(old,new [,maxreplace]

替换一个字符串

s.split([sep [,maxsplit]])

将sep作为分隔符对字符串进行划分,maxsplit是划分的最大次数

s.strip([chrs])

删掉chrs开头和结尾的空白或chrs字符

s.upper()

将一个字符串转换为答谢形式

6、扩展:python中的编码问题

    前面我们说过:python2.x中的系统缺省编码为ascii,Python3.x中的系统缺省编码为utf-8

6.1、python中编码设置介绍

    系统的缺省编码(一般就是ascii):sys.getdefaultencoding()

    系统当前的编码:locale.getdefaultlocale()

    文件系统的编码:sys.getfilesystemencoding()

    终端的输入编码:sys.stdin.encoding

    终端的输出编码:sys.stdout.encoding

    代码的缺省编码:文件头上# -*- coding: utf-8 –*-

    系统缺省的编码(sys.getdefaultencoding()):python2.x默认源代码文件是ascii编码,这个缺省编码在Python转换字符串时用的到。首先明白,一个文件以某种编码格式保存后,str存储的字节流就是这种编码格式对应的字符编码。Python3.x中的系统缺省编码为utf-8,python3.x中的str默认是unicode编码,系统编码采用utf-8便捷。

例如:

情况一:缺省头部声明

#源文件以GBK保存,你好-对应的字符编码:\xc4\xe3\xba\xc3

Python2.x中:

str1='你好,python' #以实际保存的编码存储:'\xc4\xe3\xba\xc3,python'

print str1    

   当载入这个.py程序的时候,python2.x试图去解析这个字节流,这是没有头文件声明,就按默认系统缺省编码(ascii)读取源码,当读到第一行时发现以ascii编码无法解析出中文对应的编码'\xc4\xe3\xba\xc3'。因此报以下错误:SyntaxError: Non-ASCII character '\xc4'。

Python3.x中:

str1='你好,python' #以实际保存的编码存储:'\xc4\xe3\xba\xc3,python'

print(str1)

    当载入这个.py程序的时候,python3.x试图去解析这个字节流,这是没有头文件声明,就按默认系统缺省编码(UTF-8)读取源码'\xc4\xe3\xba\xc3,python'。UTF-8中找不到对应的编码,因此报以下错误:SyntaxError: Non-UTF-8 character '\xc4'。

情况二:头部声明与存储格式不一致(注:文件实际保存GBK,头部声明为utf-8)

Python2.x中:

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

str1='你好,python'

print str1

报错:UnicodeDecodeError: 'utf8' codec can't decode byte 0xc4 in position 0: invalid continuation byte。文件实际存储的GBK的编码,而我们在头部声明了编码,当python解释器读取源代码时,没有声明读取方式则系统的缺省编码读取,声明了则按头部声明读取,而我们保存的GBK一个中文两个字节,而UTF-8一个中文要三个字节,并且UTF-8是有BOM的,头部和声明不一致,可能导致乱码,甚至会出现编码错误,此处就出现编码错误。

Python3.x中:

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

str1='你好,python'

print(str1)

报错:SyntaxError: (unicode error) 'utf-8' codec can't decode byte 0xc4 in position 0:invalid continuation byte。原因与上同。

    注:代码的缺省编码(# -*- coding: utf-8 –*-):是一个.py文件解析时的编码格式。即,以一种编码保存后,之后python解释器读取源文件的时候,要按照一定的编码去读取源码文件。解析文件的时候遇到的str都会以此编码进行解析。所以要尽量保证保存时文件的编码格式要和声明的编码格式一致。

系统当前的编码(locale.getdefaultlocale())用于查看运行环境windows/Unix/Linux系统的编码,易于实现国际化。

>>> import locale

>>> locale.getdefaultlocale()#注:查看系统当前的字符编码,cp936代表的GBK编码

('zh_CN', 'cp936')

文件系统的编码(sys.getfilesystemencoding()):

>>> sys.getfilesystemencoding()  #python2.x中

'mbcs'                           

>>> sys.getfilesystemencoding() #python3.x中

'utf-8'

终端的输入编码(sys.stdin.encoding):

>>> sys.stdin.encoding

'cp936'

终端的输出编码(sys.stdout.encoding):

>>> sys.stdout.encoding      

'cp936'

注:这里的终端大概指的是运行环境,DOS上运行输出始终和系统设置语言一样是GBK,而PyCharm里的输入输出编码因其设置而不同。

6.2、python2.x字符编码问题

    在python2.x中,使用unicode类型作为编码的基础类型,编解码要以其为中间形式过渡,即进行str和unicode之间的转换。

    解码然后再编码的过程,即:str->unicode->str的过程。中间得到的叫做unicode对象。这里需要强调的是unicode是一种字符编码方法,是“与存储无关的表示”,而utf8是一种以unicode进行编码的计算机二进制表示,或者说传输规范。

    str->unicode->str:str字符串是原字符串使用特定的编码方式得到的字节流,如果知道了该编码方式,就可以使用decode(解码)函数把str字节流解码为原字符串的Unicode对象。方式:

str_obj.decode(‘字符编码’)

unicode(str_obj,‘字符编码’)

    而unicode对象也可以使用encode(编码)函数编码为对应的字节流。方式:uniocde_obj.encode(‘字符编码’)

例如:unicode对象编码过程

>>> sys.stdout.encoding

'cp936'

>>> str1='你好'

>>> str1

'\xc4\xe3\xba\xc3'

>>> str1.decode('GBK')  #将字节序列解码为unicode对象

u'\u4f60\u597d'

>>> print str1.decode('GBK') #说明一

你好

>>> str_u=u'你好'

>>> print str_u      #Unicode对象

你好

>>> print str_u.encode('GBK')   #GBK字节流

你好

>>> print str_u.encode('UTF-8') #UTF-8字节流 #说明二

浣犲ソ

注:说明一:实际上print 语句输出unicode对象时会默认使用sys.stdout.encoding编码转换。str1.decode('GBK')转为unicode对象后,如果没有显示的进行解码,系统会默认使用str1.decode('GBK').encoding(sys.stdout.encoding)说明二:如果显示的指定了编码,此时就转为str对象,就不会为我们进行编码。

例如:str解码为unicode对象    

>>> import sys

>>> sys.stdout.encoding

'cp936'

>>> sys.getdefaultencoding()

'ascii'

>>> str1='你好'

>>> str1.decode('gbk')

u'\u4f60\u597d'

>>> print str1.decode('gbk')  #说明一

你好

>>> str1.encode('gbk')    #说明二

    Traceback (most recent call last):

    file "<pyshell#3>", line 1, in <module>

    str1.encode('gbk')

    UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 0: ordinal not in range(128)

    #注:说明一:将str字节流解码后得到是unicode对象,再使用print语句就回到了上面案例的过程中。

    说明二:如果我们直接对str字节流进行编码,没有显示的先进行解码,那么系统就会为我们先解码为unicode对象。即:str1.decode(sys.getdefaultencoding())因为此时默认的系统编码就是ascii,所以会报这个错误。但是这个问题是可以解决的。方式如下:

>>> import sys

>>> reload(sys)

>>> sys.setdefaultencoding('gbk')

注:不要试图在IDLE中运行:这会出现BUG,运行后我们就不能输出了。在DOS中的默认编码是GBK,在DOS中运行.py程序使用print语句应该注意这个问题。在对字节流进行encode(编码)前会默认使用默认编码先进行一次decode(解码)

6.3、python2.x解决字符编码问题的方法

    方式一:

    最好的方式都使用unicode对象。将所有的str字节流都解码成unicode,不去混用str和unicode对象。程序内部均使用unicode,而输出的时候,则尽早将其编码成字节流。

或者可以使用:设置 Sublime Text 的 Python Build System 环境变量

    方式二:

>>> import sys
>>> reload(sys)
>>> sys.setdefaultencoding('utf-8')

  注:修改默认编码,这种方法虽然可以,但是可能会导致一些奇怪的问题。优先使用前一种方法。

6.4、python3.x中的字符编码问题

    在python3.x中,使用str类型作为编码的基础类型,编解码要以其为中间形式过渡,即进行bytes和unicode之间的转换。

    解码然后再编码的过程,即:bytes->str(unicode)->bytes的过程。中间得str字符串(unicode字符串)。

    str->unicode->str:str字符串是unicode字符串,内置了encode()方法将其编码为对应的bytes类型的字节序列。而bytes字节类型内置了decode()方法将其解码为str字符串。

    方式:str.encode     -> bytes    bytes.decode   -> str

例如:

>>> str1='你好,python'

>>> str1.encode('gbk')

b'\xc4\xe3\xba\xc3,python'

>>> str2=str1.encode('gbk')

>>> str2.decode('gbk')

'你好,python'

6.5、python2.x与python3.x中的字符串异同

python2.x中的str 

Python3.x中的str

异同

 工厂函数:

str(object='')-> str

 

工厂函数:

str(object='') -> str

str(bytes_or_buffer[, encoding[, errors]]) -> str

python2.x中str返回字节序列.字符串和字节序列混为一谈。而python3.x返回的是unicode字符串。而把二进制明确的归为bytes类型。

str.encode()

str.decode()

str.encode()

[bytes.decode()]

python2.x中str内置了编码解码方法,而python3.x中str只有解码方法。

Python3.x中str就是unicode字符串,而不再使用unicode对象了。

三、序列-列表类型

1、列表概述

   列表元素用中括号[ ]包裹,可包裹任意对象的有序几集合,通过索引访问其中的元素,元素的个数及元素的值可以改变(可变类型)。

列表的定义格式:

    li=[] 或者 li=list() #创建一个空列表

    li=[...] 或者 li=list(iterable)

例如:

>>> li=[]

>>> li=[1,2,3]

>>> list()

[]

>>> list('abc')

['a', 'b', 'c']

>>> list((1,2,3))

[1, 2, 3]

2、列表操作

2.1、访问列表元素

方式一:索引,列表也是序列。

方式二:迭代,序列都支持迭代。

例如:

>>> l1=['a','b','c','d']

>>> l1[1]

'b'

>>> for item in l1:

    print(item)

a

b

c

d

2.2、更新列表元素

方式一:根据索引

方式二:使用append方法

例如:    

>>> l1[0]=1

>>> l1

[1, 'b', 'c', 'd']

>>> l1.append('e')

>>> l1

[1, 'b', 'c', 'd', 'e']

2.3、删除列表元素

方式一:使用del操作符

方式二:使用remove()方法

例如:

>>> del l1[0]

>>> l1

['b', 'c', 'd', 'e']

>>> l1.remove('e')

>>> l1

['b', 'c', 'd']

2.4、比较列表大小

例如:

>>> l1=['a','b','c']

>>> l2=['a','c','b']

>>> l1==l2

False

>>> l1<l2

True

注:列表比较大小,会将两个列表的元素依次比较,直到有一方的元素胜出,就得出结果了。

3、列表常用函数

序列函数

函数

描述

len(list)

列表的元素

max(list)/min(list)

最大元素/最小元素

sorted(list)/reversed(list)

排序(小到大)/倒叙(颠倒元素)

enumerate(list)/zip(list1 [,list2])

遍历方式

sum(list)

求一个列表中的总值(纯数字列表)

列表内建函数

append(obj)

向列表中添加一个对象obj

count(obj)

返回指定元素在列表中出现的次数

extend(iterable)

通过迭代的方式添加元素,要添加的元素是支持迭代的序列,无返回值,直接对原列表进行修改

index(value,[start, [stop]])

返回指定元素的索引

pop([index])

弹出(删除)元素不写索引默认最后一位,返回弹出的元素

remove(value)

删除指定元素,不存在则报错

reverse()

将列表逆序排列,无返回值,直接对原列表进行修改

sort()

对列表进行排序,无返回值,直接对原列表进行修改

例如:

>>> l1=['a','b','c']

>>> for i,item in enumerate(l1):

    print 1,item

1 a

1 b

1 c

>>> l2=[1,2,3]

>>> for i,j in zip(l1,l2):

    print '%s %s' %(i,j)

a 1

b 2

c 3

四、序列-元祖类型

1、元组概述

    元组元素用小括号( )包裹,不可变对象。不可以更改(但不意味着,里面包含的可变对象不可更改)。元组可以看成是只读的列表。

元组的定义格式:

atuple=() 或 atuple=tuple()   #创建空元组

atuple(a,b,c) 或 atuple((iterable) #创建元组

注:也可以不带()创建,即:atuple=1,2,3,4...

例如:  

 >>> aTuple =('robots',77,88,'try')

 >>> aTuple

 ('robots', 77, 88, 'try')

 >>> aTuple[1]=5  #注:TypeError不支持修改

 Traceback (most recent call last):

   file "<pyshell#208>", line 1, in <module>

   aTuple[1]=5

   TypeError: 'tuple' object does not support item assignment

>>> t=123,456,789,'hello'  

>>> t

(123, 456, 789, 'hello')

>>> t2=(1,2,[3,4])

>>> t2[2][0]='a'

>>> t2

(1, 2, ['a', 4])

>>> ('3')#试图创建一个元素元组的时候,没逗号外部的()会被当做分隔符

'3'

>>> ('3',)   #记得加上一个逗号,表明()不是分隔符

('3',)  

   #注:元组在输出时总是有括号的,以便于表达式嵌套结构。在输入时可能有或没有括号都可以。虽然元组本身不可变,但是如果元组内嵌套了可变类型的元素,那么此类元素的修改不会返回新的元组。

2、元组的操作及函数

常用方法

描述

count(value)

返回指定元素出现的次数

index(value [start, [stop]])

返回指定元素的索引

五、字典(映射)类型

1、字典概述

    字典在其他语言中又被称作关联数组或散列表。字典是 Python 中的映射数据类型,由键-值(key-value)对构成。

    序列是以连续的整数为索引,与此不同的是,字典以关键字为索引,关键字可以是任意不可变类型,通常用字符串或数值。如果元组中只包含字符串和数字,它可以做为关键字,如果它直接或间接的包含了可变对象,就不能当做key键值。不能用列表做关键字,因为列表可以用它们的append() 和 extend()方法,或者用切片、或者通过检索变量来即时改变。值可以是任意类型的 Python 对象,字典元素用大括号{ }包裹。

字典的定义格式:

d= {}  #空字典

d1={key1:value1,key2:value2,......}

链表中存储关键字-值对元组的话,字典可以从中直接构造:

d2=dict([(‘x’,’y’),(...)])    或    dict(zip(‘xyz’,’123’)

    注:字典中的键必须是可哈希的。所有的不可变类型都是可哈希的,因此他们可以作为字典的键。一个键只能对应一个值,字典键重复赋值,只取最后的。

    注:哈希表是一种数据结构,哈希表的算法是获取键,对键执行一个叫做哈希函数的操作,并根据计算的结果(一定的算法,算出下标),选择在数据结构的某个地址来存储对应的值。任何一个值的存储,取决于它的键。所以哈希表中的值是没有顺序的。

2、映射类型操作符

操作符/函数

描述

[]

字典键查找操作符,d[k] -->value

in / not in

成员关系操作符,判断是否存在某个key值

len(d)

返回字典的长度

cmp(d1,d2)

比较两个字典的大小,从左往右,一项比,先比较第一项key值,相同则比较value值

hash(obj)

返回obj的哈希值,对象不可哈希,则报错

3、字典的内建函数

常用方法

描述

clear()

清空字典中所有元素

copy()

浅复制该字典,返回字典的一个副本

formkeys(seq[,val])

创建一个字典使用seq中的元素作为key值,无val,value默认为None

get(key[,d])

返回key对应的value值,如无此key值则返回d,d不写默认为None

has_key(k)

判断有无Key,有则返回True,无则返回False

items()

Python3.x中相当于python2.x中的viewitems(),可以使用lits(dict.items)-->list   [(‘’,’’),...(‘’,’’)]

python2.x返回返回二维元组的list   [(‘’,’’),...(‘’,’’)]

iteritems()

返回一个迭代器对象,包含每一项(k,v)

iterkeys()

返回一个迭代器对象,包含每一项key值

itervalues()

返回一个迭代器对象,包含每一项value值

keys()

Python3.x中相当于python2.x中的viewkeys()

Python2.x返回key的list    -->[key1,key2...]

pop(k[,d])

删除一个具体的key,返回该key值对应的value,未找到对应的key报错

popitem()

随机删除一个键值对,返回该键值对的二维元组

setdefault(k[,d])

如果存在key值,就返回对应的value,如果不存在key值,就在字典中添加一个键值,key:d,如果d不写,默认是None

update([E, ]**F)

更新一个字典,如果有相同的key,则更新value,如果没有则插入键值。例如:>>> d2={'a':1} >>> d3={'a':'a','b':2} >>> d2.update(d3)>>> print d2  {'a': 'a', 'b': 2}

values()

返回value的list   -->> [value1,value2...]

viewitems()

dict_items([(key1, value1), (key2, value2)...)

viewkeys()

dict_keys([key1, key2...])

viewvalues()

dict_keys([value2, value2...])

注:灰色的是python2.x中存在的方法,python3.x中已经没有了

例如:

>>> aDict = {'localhost': '127.0.0.1'} #创建字典

>>> aDict['port'] = 80 #添加数据

>>> aDict

{'port': 80, 'localhost': '127.0.0.1'}

>>> aDict.keys()  #注:获取字典中所有的key值

['port', 'localhost']

>>> aDict['port']  #注:获取key对应的value值

80

>>> for key in aDict: print(key,aDict[key]) #注:遍历字典

port 80

localhost 127.0.0.1

>>> del aDict['port']

>>> aDict

{'localhost': '127.0.0.1'}

注:字典和列表的区别

    无论dict有10个元素还是10万个元素,查找速度都一样。而list的查找速度随着元素增加而逐渐下降。不过dict的查找速度快不是没有代价的,dict的缺点是占用内存大,还会浪费很多内容,list正好相反,占用内存小,但是查找速度相对dict慢。

4、扩展-浅拷贝和深度拷贝

   拷贝可分为浅拷贝和深度拷贝

   浅拷贝:只拷贝父对象,不会拷贝对象的内部的子对象

   深度拷贝:拷贝对象及其子对象

例如:

>>> import copy

>>> a=[1,[2,3],4]

>>> b=a

>>> c=copy.copy(a)       #注:浅拷贝

>>> d=copy.deepcopy(a)   #注:深度拷贝

>>> print(id(a),id(b),id(c),id(d))

50068872 50068872 50011336 50074824   

#说明:=是赋值操作,直接将b指向了a的引用,都指向同一块内存地址。

#copy()操作和deepcopy()操作的id都已发生变化了。即c、d指向的内存地址发生改变了。

     

>>> a.append(5)   #注:对a进行修改

>>> print(a,b,c,d)   #注:因为a、b都指向的是一片内存地址对a修改b自然受到影响

[1, [2, 3], 4, 5] [1, [2, 3], 4, 5] [1, [2, 3], 4] [1, [2, 3], 4]

>>> a[1].append(6) #注:对内部子对象进行修改

>>> print(a,b,c,d)  #注:a、b、c都发生改变了,只有深度拷贝内部子对象没有受到影响

[1, [2, 3, 6], 4, 5] [1, [2, 3, 6], 4, 5] [1, [2, 3, 6], 4] [1, [2, 3], 4]

注:列表和字典都支持两种类型的复制操作:浅拷贝和深度拷贝。深度拷贝可使用copy模块中的deepcopy()实现。

六、集合类型

1、集合概述

   集合对象是一组无序排列的可哈希的值。集合成员可以做字典中的键。

   dict的作用是建立一组key和一组value的映射关系,dict的key是不能重复的。有的时候,我们只想要dict的key,不关心 key 对应的 value,目的就是保证这个集合的元素不会重复,这时,set就派上用场了。set 持有一系列元素,这一点和 list 很像,但是set的元素没有重复,而且是无序的,这点和 dict 的 key很像。集合有两种不同的类型:可变集合(set)和不可变集合(frozenset)。

   对于集合set对象来说,是可变集合,是不可哈希的,因此set对象不能作为字典的键,但是它里面的元素可以。而对于frozenset对象来说,是不可变集合,它是可哈希的,能被作为字典的键。

可变集合set定义语法:

s=set()  #创建一个空集合

s=set(iterable) #通过一个可迭代对象创建,里面的元素必须是可哈希的

不可变集合frozenset定义语法:

s=frozenset()  #创建一个空集合

s=frozenset(iterable)
例如:

>>> l1=[1,2,3,3,2,1]

>>> set(l1)

set([1, 2, 3])

>>> l2=[l1,2,3,4]

>>> set(l2)    #注:可迭代序列l2中包含了不可哈希元素

Traceback (most recent call last):

  file "<pyshell#3>", line 1, in <module>

    set(l2)

TypeError: unhashable type: 'list'

2、集合类型的操作符

操作符/函数

描述

in / not in

判断是否是成员关系

==/!=

等于/不等于

s < t

s是t的(严格)子集

s > t

s是t的(严格)超集

s >= t

s是t的(非严格)超集

s & t

s 和t的交集

s | t

s和t的合集

s - t

差集

s ^ t

对称差集

len()

集合中的项数

3、可变集合set的内建函数

方法/操作

描述

add(...)

添加一个元素到s集合中

clear()

清空集合项

copy()

浅复制一个s集合的副本

difference(t)

求差集,返回所有在s中但不在t中的项(不会改变s)

difference_update(t)

求差集,直接移除s中在t中也出现的项,默认返回None(改变原有集合s)

discard(...)

移除一个元素,如果存在就移除,不存在就不做什么

intersection(t)

求交集,返回所有在s和t中的项目

intersection_update(t)

求交集,直接更新s集合作为交集,默认返回None(改变原有集合s)

isdisjoint(t)

如果s和t没有相同项,则返回True

issubset(t)

如果s是t的一个子集,则返回True

issuperset(t)

如果s是t的一个超集,则返回True

pop()

随机移除一个元素,没有元素移除将会报错

remove(...)

移除set集合中的一个元素,如果不存在这个元素就会报错

symmetric_difference(t)

求对称差集,返回所有在s或t中,但又不同时在这两个集合中的项(不会改变原有集合s)

symmetric_difference_update(t)

求对称差集,s集合会变更为对称差集(会改变原有集合s)

union(t)

求并集,返回所有在s或t中的项(不会改变原集合s)

update(t)

求并集,更新s集合为新的s和t的并集(会改变原集合s)

4、不可变集合frozenset的内建函数

方法/操作

描述

copy()

浅复制一个s集合的副本

difference(t)

求差集,返回所有在s中但不在t中的项(不会改变s)

intersection(t)

求交集,返回所有在s和t中的项目

isdisjoint(t)

如果s和t没有相同项,则返回True

issubset(t)

如果s是t的一个子集,则返回True

issuperset(t)

如果s是t的一个超集,则返回True

symmetric_difference(t)

求对称差集,返回所有在s或t中,但又不同时在这两个集合中的项(不会改变原有集合s)

union(t)

求并集,返回所有在s或t中的项(不会改变原集合s)

第三章 python中的语句或表达式

一、基本概述

1、语句

     语句,是程序中最小的独立单元,通常以行为单位。语句可以包含表达式,表达式也可以单独形成一个语句。(语句最明显的标志为分号结束。但并不是什么时候都会有分号,一条语句独占一行时可以不写分号)。

    Python中的常见语句:

    赋值语句:简单赋值(=)、多重赋值(x1=x2=3)、增强赋值(+=、-=...)

    调用:执行函数(打印语句:print,python2.x中是语句,python3.x中已是函数)

    条件判断语句:if/elif/else;

    迭代循环:for/else

    普通循环:while/else

    其他语句:pass语句、break语句、continue语句、return语句、raise:触发异常、del:删除引用语句、assert:调试检查、class:类定义语句、try/exception/finally:捕捉异常语句、def:函数定义语句、import:模块导入语句、from:模块属性访问

    with/as:环境管理器......

2、表达式

   表达式,由一个或多个操作数构成,每个表达式都会产生一个结果,即返回值(表达式是可以用来计算的式子,最终都会有一个值体现)。表达式的作用有两点,一个是放在赋值语句的右边,另一个是作为函数的参数。应用在操作数上的操作由操作符表示。作用在一个操作数上的操作符被称为一元操作符。作用在两个操作符上的操作符被称为二元操作符。两个或两个以上的操作符被组合起来的时候被称为复合表达式。

例如:

a=35;  #语句

b=1+a; #整个式子是语句,但是1+a就是表达式

    三元选择表达式:result = x if y else z(如果y为真result=x,如果y为假result=z)  -->  注:红色部分x if y else z就是三元表达式。

>>> a1=7

>>> a2=8

>>> A=a1 if a1>a2 else a2

>>> A

8

3、语句详解

3.1、条件语句

条件语句语法格式:

if  boolean_expression1:

   statement1

[elif boolean_expression2:   #注:可选部分

   statement2]

else:

   statement3

   注:python中以缩进标记代码的边界。

   注:False:0,None,空对象都会返回False,其他都为True

   注:and,or和not在逻辑判断上与其他语言相同,但是注意and和or的返回

3.2、while语句

while语句语法格式:

while bool_expression:

    statement1

[else:

    statement2]

   注:while循环可包含else分支为可选,bool_expression为False时执行,但是else用的比较少。表达式判断循环是否结束。

3.3、for语句

for语句语法格式一:

for iter_var in iterable:

    statement1

for语句语法格式二:

for item_index in range(len(seq)):

    statement1

扩展:range()内建函数介绍

range()语法:

range(stop) -> list of integers

range(start, stop[, step]) -> list of integers

    range()函数会返回一个范围的list列表,range(start, stop[, step])可以定义一个步长,生产对应的list列表。

xrange()语法:

xrange(stop) -> xrange object

xrange(start, stop[, step]) -> xrange object

    xrange()类似于range(),但是去遍历一个很大的范围时,xrange()更适合,他不会再内存里创建列表的完整拷贝。只在for循环中,在for循环外没有意义。他返回一个xrange()对象(不是列表,也不是一个迭代器)。他的性能远远高于range()。但是python3.x中取消了python2.x中的range,并且将xrange重新定义为range

例如:

>>> li=['a','b','c','d']

>>> for index in range(len(li)):

    print(li[index])

a

b

c

d

>>> type(xrange(10))   #python2.x中才有,python3.x中为range

<type 'xrange'>

>>> range(10) #python3.x中,返回一个range对象

range(0, 10)

>>> list(range(10)) #python3.x中实现python2.x中的range

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

3.4、break、continue、pass语句

    a)break语句

   break语句可用在while和for循环中,作用是跳出循环

   b)continue语句

    continue语句可用在whiel和for循环中,作用是终止当前循环,进行下一次循环。

   c)pass语句

   pass语句,作用是不做任何事情。

例如:

>>> def func():

    pass    注:表示里面不做任何事情。

注:这样简化了操作,有些定义格式下面必须写上语句,直接写pass更方便

4、迭代器(iterator)和iter()函数

4.1、迭代器概述

    迭代器,它为序列对象提供一个类序列的接口。Python中的迭代可以迭代序列对象,也可以得带非序列类型,包括用户自定义对象。

    迭代器需要遵循以下协议:对象必须提供一个next()方法,执行该方法时,要么返回迭代中的下一项,要么引起一个StopIteration异常。迭代器只能往前访问,不能向后移动,也不能回到开始。在python中,支持迭代协议就是实现对象的__iter__()和__next__()方法。

    __iter__()方法:返回迭代器对象本身;

    __next__()方法:返回容器中的下一个元素,在结尾时引发StopIteration异常终止迭代器。

    内置函数iter()、next(),本质上都是用的对象的__iter__()、__next__()的方法。

    reversed() 内建函数将返回一个反序访问的迭代器. enumerate() 内建函数同样也返回迭代器.

    另外两个新的内建函数, any() 和 all() , 在 Python 2.5 中新增, 如果迭代器中某个/所有条目的值都为布尔真时,则它们返回值为真。 Python 还提供了一整个 itertools 模块, 它包含各种有用的迭代器。

例如:自定义迭代器

>>> class MyRange(object):

    def __init__(self, n):

        self.idx = 0

        self.n = n

    def __iter__(self):

        return self

    def next(self):

        if self.idx < self.n:

            val = self.idx

            self.idx += 1

            return val

        else:

            raise StopIteration()

>>> myrange=MyRange(5)

>>> myrange.next()

0

>>> myrange.next()

1

注:此处没有用for循环迭代,是因为在python3.x中for循环中对迭代的对象进行了校验,使用之后抛出如下错误:iter() returned non-iterator of type 'MyRange'。但是在python2.x中就可以正常迭代。

4.2、可迭代对象(iterable)

   实现了迭代器协议的对象,就是可迭代对象。

   如何实现迭代器协议:对象内部定义了一个__iter__()方法。

   在Python中,list、tuple、dict、set以及生成器对象都是可迭代对象。如果不确定哪个可迭代,可以使用内置函数iter()测试。

   所有的iterable均可以通过内置函数iter()转化为iterator语法如下:

   iter(collection) -> iterator

   iter(callable, sentinel) -> iterator

例如:

>>> iter([1,2,3]) #返回listterator对象
<list_iterator object at 0x0000000002C75340>
>>> iter(666)
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    iter(666)
TypeError: 'int' object is not iterable
>>> 

4.3、迭代器的优点

   a)对于支持随机访问的数据结构:list、tuple等,迭代器和经典的for循环(索引访问)相比,并无优势,反而失去了索引值。不过可以使用内置函数enumerate()找回这个索引值。但对于无法随机访问的数据结构:set(),迭代器是唯一的访问元素的方式。

   b)省内存:迭代器不需要事先准备好整个迭代过程中的所有元素,仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或销毁。这也是迭代器的一大优点:适合用于遍历一个巨大的或无限的集合,比如几个G的文件。

第四章 文件对象及输入输出

一、文件对象

1、文件基本概述

   文件是计算机中由os(操作系统)管理的具有名字的存储区域。通常用户交互、读写文件、访问网页等,我们称之为输入和输出(I/O)。文件对象不仅可以用来访问普通磁盘文件,而且可以访问其他类型抽象层面上的文件。文件分为:文本文件和二进制文件。

    file对象也是一个可迭代对象。

1.1、Python的内置函数:open()

  open()用于打开文件和创建文件对象。

语法格式:

  open(name [,mode[,bufsize]]) --返回file 对象

  name:文件名

  Mode:模式-文件打开的模式,不写默认以读方式打开

  bufsize:定义输出缓存

          0-表示无输出缓存

          1-表示使用缓冲

          负数-表示使用系统默认设置

          正数-表示使用近似指定大小的缓冲

与之等效的方式:file()-文件对象内建方法

  file(name[, mode[, buffering]]) -> file object

例如:

>>> f1=open(r'C:\mypython\test.txt','r')

>>> s=f1.read()

>>> print(s)

你好,python

2、文件访问模式 

文件模式

操作

说明:[r:只读,w:写入,a:附加]

      + 表示同时支持输入、输出操作(可读、可写)

      附加b 表示以二进制方式打开

      U表示换行符:不同平台换行符可能不同。\n \r

注:b对于unix/linux系统来说,可有可无,因为它们把所有的文件都当做二进制文件。b不能作为第一个字符出现

r

以读方式打开(此方式打开的文件必须已存在)

rU/Ua

以读方式打开,同时提供通用换行符支持

w

以写方式打开(文件若存在先清空,然后重新创建)

a

以追加模式打开(从EOF(end of file)开始,必要时创建新文件)

r+

以读写模式打开。文件内容不清空,但会从头开始替换新内容

w+

以读写模式打开。一旦调用文件内容清空,可重新写入

a+

以读写模式打开。在文件尾部追加。

rb

以二进制读模式打开

wb

以二进制写模式打开

ab

以二进制追加模式打开

rb+

以二进制度读写模式打开

wb+

以二进制度读写模式打开

ab+

以二进制度读写模式打开

3、文件对象的内置方法

文件对象方法

描述

file.close()

关闭文件,关闭后不能进行读写。不显示关闭文件,那么可能丢失输出缓冲区中的数据。

file.fileno()

返回文件的描述符

file.flush()

刷新文件的内部缓冲区,直接把内部缓冲区的数据立刻写入文件,而不是被动的等待输出缓冲区写入。默认返回None。

file.isatty()

判断file是否是一个tty设备(是否连接到一个终端设备)

file.next()

返回文件的下一行,如没下一行是报错

file.read([size])

从文件读取size个字节,当为给定size或给定负值的时候,读取剩余的所有字节,作为字符串返回,没给定size默认为-1

file.readinto(buf,size)

从文件读取size个字节到buf缓冲器(已废弃)

file.readline([size])

从文件中读取并返回一行(包括结束符),或者返回最大size个字符

file.readlines([size])

从文件读取所有行并作为一个列表返回(包含所有行的结束符),如果给定size且大于0,那么将返回总和大约为size字节行。

file.xradlines()

用于迭代,可以替换readlines()的一个更高效的方法

file.seek(offset[, whence])

从文件中移动文件指针,从where(0代表文件起始,1代表当前位置,2代表文件末尾)偏移offset字节,默认返回None

file.tell()

返回当前在文件中的位置,返回integer

file.truncate([size])

截取文件到最大size字节,默认为当前文件位置,默认返回None

file.write(str)

向文件写入字符串,默认返回None

file.writelines(seq)

项文件写入字符串序列seq,默认返回None

 

文件对象属性

描述

file.closed

True表示文件已经被关闭,否则为False

file.encoding

文件所使用的编码-当unicode字符串被写入数据时,他们将自动使用file.encoding转换为字节字符串。若file.encoding为None时使用系统默认编码

file.mode

文件打开时使用的访问模式

file.name

文件名

file.newlines

未读取到行分隔符时为None,只有一种行分隔符是为一个字符串,当文件有多种类型的行结束符是,则为一个包含所有当前所遇到的行结束符的列表

file.softspace

为0表示在输出一数据后,要加上一个空格符,1表示不加。这个属性一般用不着,有程序内部使用

例如:

>>> f1=open(r'C:\mypython\test.txt')

>>> content=f1.read()

>>> print(content)

你好,python

你好,我是第二行

>>> f1=open(r'C:\mypython\test.txt','a+')

>>> f1.write('你好,我是写入\n')

>>> f1.close()   #注:关闭时,会强制写入文件,不加这句则还未真正写入



>>> f1=open(r'C:\mypython\test.txt')

>>> f1=open(r'C:\mypython\test.txt','a+')

>>> f1.write('你好,我是写入\n')

>>> f1.flush()  #注:此刻缓冲区中的数据被写入文件

>>> f1.close()



>>> f1=open(r'C:\mypython\test.txt')

>>> for line in f1:

    print(line)

你好,python

你好,我是第二行你好,我是写入

你好,我是写入

>>> f1=open(r'C:\mypython\test.txt')

>>> data=[line.strip() for line in f1.readlines()]

>>> f1.close()

>>> for line in data:

    print(line)

你好,python

你好,我是第二行你好,我是写入

你好,我是写入

二、文件系统

1、基本概述

   对文件系统的访问,大多数通过python的os模块实现。Os模块是python访问操作系统的主要接口。除了对进程和进程运行环境进行管理外,os还负责了大部分的文件系统操作。os.path模块可以完成一些针对路劲名的操作。

   操作系统相关模块的名字:

   Windows      (os.name-->)        nt

   Linux/Unix   (os.name-->)        posix

   DOS          (os.name-->)        dos

   OS/2         (os.name-->)        os2(微软最终放弃OS/2转向windows)

2、os模块的内建属性/方法

属性/方法

描述

属性

os.name

执行平台的类型

os.linesep

当前平台使用的行终止符号,windows下为‘\r\n’,linux下为‘\n’

os.sep

输出操作系统特定的路劲分隔符

os.pathsep

分隔文件路劲的字符串,windos下;

os.curdir

返回当前目录(‘.’)

os.pardir

获取当前目录的父目录(‘..’)

os.environ

获取系统的环境变量

方法

文件处理

remove(path)/unlink(path)

删除一个文件

rename(old, new)/

renames(old, new)

重命名文件

stat()/lstat()

获取文件/目录信息[st_mode(权限模式)、st_ino、st_dev、st_nlink、st_size(文件字节大小)、st_atime(最近一次访问时间)、st_mtime(最近修改时间)、st_ctime(平台相关,unix下最近一次元数据修改时间,window下创建时间]

utim(path, (atime, mtime))

更新时间戳

tmpfile()

创建一个新的临时文件(没有目录)

walk(top,topdown=True, οnerrοr=None, followlinks=False)

生成一个目录树下的所有文件名:top表示需要遍历的目录树路径。Topdown的默认值为True,表示先返回目录树下的文件,然后在遍历目录树的子目录,为False时,表示先遍历目录树的子目录,返回目录下的文件,最后再返回根目录下的文件。Onerror的默认值是None,表示忽略文件遍历时产生的错误,如果不为空,则提供一个自定义函数提示错误信息后继续遍历或抛出异常中止遍历。

目录/文件夹

chdir(path)

改变当前脚本的工作目录,相当于shell下cd

listdir(path)

列出指定目录下的所有文件和字目录,包括隐藏文件-返回字符串list

getcwd()/getcwdu()

获取当前工作目录,即当前python脚本工作的目录路径--返回字符串str/后面的返回unicode形式字符串。

mkdir(path[, mode=0777])

创建目录(单级)

makedirs(name, mode=511)

创建多层目录(递归)

rmdir(path)

删除单级目录,若目录不为空无法删除,报错

removedirs(path)

若目录为空,则删除,并递归到上一级,若也为空,则删除...

访问/权限

access(path, mode)

检验权限模式,返回bool类型

chmod(path, mode)

改变权限模式

umask(new_mask)

设置默认权限模式

文件描述操作符

 

open(filename,flag[,mode=0777])

底层的操作系统open--返回fd,即文件描述符(对于文件使用内置函数open)

read(fd,buffersize)/write()

根据文件描述符读取/写入

dup(fd)

赋值文件描述符-返回fd2

dup2(old_fd, new_fd)

赋值到另一个文件描述符设备号

其他方法

system(command)

运行shell命令--返回exit_status

例如:

>>> fd=os.open(r'E:\mypython\test.txt',os.O_RDWR)

>>> r=os.read(fd,12)

>>> print(r)

'\xc4\xe3\xba\xc3\xa3\xacpython'

>>> print(r.decode('gbk'))

你好,python

3、os.path模块内建方法

方法

描述

basename(p)

去掉目录路径,返回文件名

dirname(p)

去掉文件名,返回目录路径

join(path, *paths)

将分离的各部分组合成一个路径名

split(p)

返回(dirname(),basename())元组

splitdrive(p)

返回(drivename,pathname)元组

splitext(p)

返回(filename,extension)元组

getatime(filename)

返回最近访问时间

getctime(filename)

返回文件创建时间

getmtime(filename)

返回最近文件修改时间

getsize(filename)

返回文件大小(以字节为单位)

exists(path)

指定路径(文件或目录)是否存在

isabs(s)

指定路径是否为绝对路径

isdir(...)

指定路径是否存在且为一个目录

isfile(path)

指定路径是否存在且为一个文件

islink(path)

指定路径是否存在且为一个符号链接

ismount(path)

指定路径是否存在且为一个挂载点

例如:

>>> import os

>>> import os.path

>>> os.name

'nt'

>>> os.getcwd()    #获取当前工作目录

'C:\\cx\\python'

>>> os.chdir('C:\mypython') #切换工作目录

>>> os.getcwd()

'C:\\mypython'

>>> os.mkdir('test')        #创建一个目录

>>> os.chdir(r'C:\mypython\test')

>>> os.getcwd()          

'C:\\mypython\\test'

>>> os.listdir('.')        #当前目录下,没有文件夹/文件

[]

>>> cwd=os.getcwd()

>>> cwd

'C:\\mypython\\test'

>>> f=open('test','w')    #写入文件

>>> f.write('line1\n')

>>> f.write('line2\n')

>>> f.close()

>>> os.listdir('.')       #当前目录下有一个文件

['test']

>>> os.rename('test','test.txt')  #重命名文件

>>> os.listdir('.')

['test.txt']

>>> path=os.path.join(cwd,os.listdir(cwd)[0]) #拼接完整的文件路径

>>> path

'C:\\mypython\\test\\test.txt'

>>> os.path.isfile(path)    #判断是否是文件

True

>>> os.path.split(path)

('C:\\mypython\\test', 'test.txt')

>>> os.remove(path)        #删除文件

>>> os.listdir(cwd)        #文件列表为空,文件被删除

[]

>>> os.pardir              #当前目录的父级目录

'..'

>>> os.chdir(os.pardir)    

>>> os.getcwd()

'C:\\mypython'

>>> os.rmdir('test')       #删除空目录

第五章 错误和异常

一、基本概述

1、错误

   a)语法错误。代码不符合解释器或者编译器语法,执行前可以修改。

   b)逻辑错误。不完整或不合法输入(传递参数不合法)或者计算出现问题(比如出现除0操作)。

2、异常

   即使是在语法上完全正确的语句,尝试执行它的时候,也可能会发生的错误。即在程序运行中检测出的错误,称之为异常。它通常不会导致致命的问题。异常类型作为错误信息的一部分。

   出现异常的原因:

   a)程序逻辑或算法问题

   b)运行过程中计算机错误(内存不够等)

  异常的两个步骤:

   异常产生,检查到错误且解释器认为是异常,抛出异常。

   异常处理,截获异常,忽略或者终止程序处理异常,减轻错误带来的影响等。

  Python的运行时错误称作异常。

    语法错误:软件的结构上有错误而导致的不能被解释器解释或不能被编译器编译

    逻辑错误:由于不完整或不合法的输入所致,也可能是逻辑无法生成、计算或者输出结果需要的过程无法执行等。

    Python异常是一个对象,表示错误或意外情况。在python检测到一个错误时,将触发一个异常。可以通过传导机制传递一个异常对象,也可以在代码中手动触发异常。

    Python异常可以理解为:程序出现了错误而在正常控制流以外采取的行为。可分为两个阶段:

    第一阶段:解释器触发异常,此时当前程序流将被打断

    第二阶段:异常处理,如忽略非致命性错误。减轻错误带来的影响等。

 Python错误处理:

    python的默认处理:停止程序,打印错误消息,也可以使用try语句处理异常并从异常中恢复。

3、常见异常

异常名称

描述

Exception

所有异常的基类

StopIteration

当一个迭代器的 next()方法不指向任何对象时引发

SystemExit

由 sys.exit()函数引发

StandardError

除了StopIteration异常和SystemExit,所有内置异常的基类

ArithmeticError

数值计算所发生的所有错误的基类

OverflowError

当数字类型计算超过最高限额引发

FloatingPointError

当一个浮点运算失败时触发

ZeroDivisonError

当除运算或模零在所有数值类型运算时引发

AssertionError

断言语句失败的情况下引发

AttributeError

属性引用或赋值失败的情况下引发

EOFError

当从 raw_input() 与 input() 函数输入,到达文件末尾时触发

ImportError

当一个 import 语句失败时触发

KeyboardInterrupt

当用户中断程序执行,通常是通过按 Ctrl+c 引发

LookupError

所有查找错误基类

IndexError

KeyError

当在一个序列中没有找到一个索引时引发

当指定的键没有在字典中找到引发

NameError

当在局部或全局命名空间中找不到的标识引发

UnboundLocalError

EnvironmentError

试图访问在函数或方法的局部变量时引发,但没有值分配给它。

Python环境之外发生的所有异常的基类。

IOError

IOError

当一个输入/输出操作失败,如打印语句或 open()函数试图打开不存在的文件时引发

操作系统相关的错误时引发

SyntaxError

IndentationError

当在Python语法错误引发;
没有正确指定缩进引发。

SystemError

当解释器发现一个内部问题,但遇到此错误时,Python解释器不退出引发

SystemExit

当Python解释器不使用sys.exit()函数引发。如果代码没有被处理,解释器会退出。

 

当操作或函数在指定数据类型无效时引发

ValueError

在内置函数对于数据类型,参数的有效类型时引发,但是参数指定了无效值

RuntimeError

当生成的错误不属于任何类别时引发

NotImplementedError

当要在继承的类来实现,抽象方法实际上没有实现时引发此异常

4、异常的检测与处理

   异常通过try语句来检测,任何在try语句中的代码都会被检测,以检测有误异常发生

   try有两种形式:

   1)try-except:检测和处理异常

       可以有多个exception

       支持else子句处理没有探测异常的执行的代码

   2)try-finally

       仅检查异常并做一些必要的清理工作,仅能有一个finallly

   复合形式:try-except-finally

语法:

   try:

       try_suite

   except exception[,reason]:

       except_suite

   except: #没有写任何原因,可以捕获一切异常

   else:  #try中没有产生任何异常才会进行

       else

   finally: #不管怎样都会执行

5、raise语句

   raise语句可以显示触发异常。法语:Raise[someException [,args[,traceback]]]

   注:someException :可选,异常名字,仅能使用字符串、类或实例

          args:可选,以元组的形式传递给异常的参数

          traceback:可选,异常触发时新生成的一个用于异常-正常化的跟踪记录

第六章 函数

一、函数概述

1、函数定义

   函数就是完成特定功能的一个语句组,这组语句可以作为一个单位使用,并且给它取个名字。使用函数的好处就是可以分解流程及减少冗余代码实现代码的重用。

语法:
def functionName([parameters])

    "function_documentation_string文档说明字符串"

     statements

     [return value]

注:def 是一个可执行语句,可以出现在任何能够使用语句的地方,甚至可以嵌套于其他语句中。如:if或while中。def相当于创建了一个对象并且将其值赋给了一个变量名(即函数名)。

注:return用于返回结果对象,其为可选;无return语句的函数自动返回None对象。返回多个值时,彼此间使用逗号分隔,且组合为元组形式返回一个对象。

注:python中函数不允许在函数未声明之前,对其行引用。

2、函数的调用方式

   和大多数语言相同,python中函数的调用方式使用:()进行调用。但是在python中函数的操作符同样用于类的实例化

   a)标准化参数(默认按参数顺序)调用:

     functionName(arg1,arg2...)

   b)关键字参数调用(不按顺序匹配):

     functionName(arg2=value2,arg1=value1...)

例如:

>>> def func1(host,port):

        print(dict([(host,port)]))

>>> func1('127.0.0.1',8080)   #注:按顺序调用

{'127.0.0.1': 8080}

>>> func1(port=8080,host='127.0.0.1')  #注:不按顺序调用

{'127.0.0.1': 8080}

注:尽量不要使用可变对象作为函数的默认值,如果参数不显示的赋值,那么所谓的参数默认值只不过是指向那个在compile阶段就已经存在的对象的指针。

例如:

>>> def func_default_args(my_list=[],element=None):

    my_list.append(element)

    return my_list

>>> list1=func_default_args(element=1)

>>> list1

[1]

>>> list2=func_default_args(element=2)

>>> list2

[1, 2]

注:python中的任何变量都是对象。Python中的参数只支持引用传递。

    值传递:被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。

    引用传递:被调函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

3、函数参数

3.1、位置参数

   位置参数,就是有一定顺序的参数,其个数和位置都要匹配,不可缺少的参数。(注:当然可将关键字参数带入,位置参数可以不按顺序匹配)

3.2、默认参数

   默认参数就是如果在函数调用时没有为参数提供值,则使用预定义的默认值。即默认参数是可选的。每个默认参数都会跟着一个默认的赋值语句,且位置参数必须出现在默认参数之前。

语法: def func(posargs,defarg1=value1,defarg2=value2...):

          “function_documentation_string”

           Statement

例如:

>>> def func(host,port=8080,stype='tcp'):

        print(host,port,stype)

>>> func('127.0.0.1',80,'udp')  #不使用默认参数

127.0.0.1 80 udp

>>> func('127.0.0.1')           #使用默认参数

127.0.0.1 8080 tcp

>>> func(port=80,host='127.0.0.1')  #唯一不能缺少的就是位置参数

127.0.0.1 80 tcp

3.3、可变长度的参数

1)非关键字可变长参数

  在函数被调用的时候,所有的形参(必须的和默认的)都将赋值给函数中声明的局部变量。剩下的非关键字参数将按顺序插入到一个元组中便于访问。使用一个星号标记。

 语法:

 def function_name([formal_args,]*vargs_tuple)

    “function_document_string”

     Statement

例如:

>>> def func(arg1,arg2,*arg3):

    print(arg1,arg2,arg3)

>>> func(1,2,3,4,5) #注:如果没有额外的参数,元组为空

1 2 (3, 4, 5)

2)关键字变量参数

  参数被放入一个字典中,字典中的键为参数名,值为相应的参数值。为了区分关键字参数和非关键字参数,使用两个星号标记。

语法:

def function_name([formal_args,][*vargs_tuple,] **vargsd)

   “function_document_string”

    Statement

例如:

>>> def func(arg1,arg2='def',**arg3):
	print(arg1,arg2,type(arg3))
	for item in arg3.keys():
		print(item,"--",arg3[item])

		
>>> func('参数1',a='1',b='2')
参数1 def <class 'dict'>
a -- 1
b -- 2

4、函数种类

    全局函数(内置函数:python内嵌的一些函数。

    自定义函数:根据自己的需求,来进行定义函数。【自定义函数可分为:普通函数、匿名函数:一行代码实现一个函数功能。(如:lambda函数:表达式(匿名函数))、递归函数】

    函数相关的语句和表达式:global 、nonlocal 、yield 、lambda

    Lambda表达式返回可调用的函数对象。Python中使用lambda关键字创建匿名函数。 语法:lambda [arg1[,arg2,...argN]]:expression   即:lambda 参数:表达式

例如:

>>> sum1=lambda x,y=2:x+y

>>> sum1(1)

3

5、generator生成器

5.1、生成器概述

   生成器的作用是一次产生一个数据项,并把数据项输出。Generator函数可以用在for循环中变量。Generator函数所具有的每次返回一个数据项的功能,使用迭代器的性能更佳。生成器还有一个很重要的特性就是在调用过程中局部变量和执行状态可以自动保存。

   优势:python对延迟提供了更多的支持。生成器会在需要的时候才产生结果,而不是立即产生结果。这样节省了内存空间,并且时间允许计算时间分散到各个请求结果。

Generator函数语法:

def functionName(args...)

    ......

    yield 表达式

例如:

>>> def reverse(data):

    for index in range(len(data)-1,-1,-1):

        yield data[index]

for char in reverse('golf'):

print(char)

f

l

o

G

>>> gen=reverse('golf') #获得了一个生成器

>>> gen.__next__() #注意:python3.x中使用__next__()去获取迭代元素

'f'                #注意:python2.x中使用next()去获取迭代元素

解释:当调用生成器函数的时候,函数返回一个生成器对象,并没有执行。当__next__()方法第一次被调用的时候,生成器才开始执行,执行到yield语句处停止。__next__()方法返回的值就是yield语句处的参数,当继续调用__next__()方法的时候,函数接着上一次停止的yield语句处执行,并到下一个yield处停止。如果后面没有yield就抛出stopIteration异常。

另外还有一种简单的方式,通过表达式生成generator,但是这种缺乏通用性。

>>> g=(x*x for x in range(10))

>>> type(g)

<class 'generator'>

5.2、迭代器iterator和生成器generator的异同

    Generator可以说是一种特殊的迭代器,内部支持了生成器协议,不需要明确的定义__iter__()和__next__()方法。生成器函数可以通过常规的def语句来定义,但是不用return返回,而是用yield一次返回一个结果。

Generator常用方法

描述

__iter__(self, /)

实现了iter()迭代器

__next__(self, /)

实现了next()

close()

关闭生成器,对关闭的生成器后再次调用next或send将抛出StopIteration异常

send(arg)

send(value)方法传入的值作为yield表达式的值

throw(typ[,val[,tb]])

抛出异常

例如:

>>> def csrange(n):

    i = 0

    while i<n:

        val = yield i

        print('val is :',val)

        i+=1      

>>> cs=csrange(5)

>>> cs.__next__()

0

>>> cs.send(99) #将send(value)将value作为yield表达式的值

val is : 99

1

>>> cs.send(None) #注:等价于调用next()/__next__()

val is : None

2

>>> next(cs)   #注:内建函数next()等价于__next__()

val is : None

3

注:调用send()方法时,生成器必须处于yield暂停状态,否则将报错。

6、部分内建函数

内建函数

描述

apply(func[,args[,kwargs]])

用可选的参数来调用func,args为非关键字参数,kwargs关键字参数,返回值是函数调用的返回值。相当于把函数参数存放在一个元组或字典中,间接调用函数。

filter(function or None, sequence)

调用一个布尔函数来迭代seq中的每个元素,返回一个使函数值为True的元素序列。如果为None,表现为一个身份函数,返回序列中不为假的所有元素。

map(function, sequence[, sequence, ...])

将函数作用于给定序列的每个元素,并用一个列表来提供返回值。如果为None,函数表现为一个身份函数,返回一个含有每个序列中元素几个的n个元组列表

 reduce(function, sequence[, initial])

将二元函数作用于序列的元素,每次携带一对,连续的将现有的结果和下一个值作为函数参数

例如:

>>> def say(a,b):

   print(a,b)

>>> apply(say,('hello','python'))

hello python

>>> def odd(n):

    return n%2

>>> print filter(odd,range(9))    #过滤掉不符合条件的元素

[1, 3, 5, 7]      #[item for item in iterable if function(item)]i

>>> print filter(None,range(9))   #过滤掉为False的元素

[1, 2, 3, 4, 5, 6, 7, 8]  #[item for item in iterable if item]

>>> map(lambda x:x*2,[1,2,3,4])   #对序列中的每项都执行函数并返回

[2, 4, 6, 8]

>>> map(None,[1,2,3,4,5,6])

[1, 2, 3, 4, 5, 6]

>>> map(None,[1,2],[3,4])

[(1, 3), (2, 4)]

>>> reduce(lambda x,y:x+y,range(5))#相当于:((((0+1)+2)+3)+4)

10

第七章 模块

一、模块概述

1、模块定义

     模块是最高级别的程序组织单元,他将程序代码和数据封装起来以便重用。每一个.py文件都是一个模块,每个模块都有自己的名称空间,python允许导入其他模块以实现代码的重用。Python中,模块也是对象,一个模块被导入时,模块顶层的所有变量名都会变成模块的属性。

    模块首次导入(或重载)时,python会立即执行模块文件的顶层程序代码(不在函数内的代码),而位于函数主体内的代码直到函数被调用时才会执行。例如:def function:...函数的定义也是顶层程序代码,定义也会执行,只是内部的代码,需要调用时才会执行。

    Python自带的模块,又叫标准库模块。使用 help('modules')可以获取当前可导入的模块。

    Python中自带了很多实用的模块,称为标准链接库。python3.8中有350多个模块,包括:操作系统接口、对象永久保存、文字模式匹配、网络和Internet脚本、GUI构建......

2、导入模块

    在导入模块时只能使用模块名,不能使用带.py后缀的模块文件名。

2.1、import语句

     导入指定的整个模块,包括生成一个以模块命名的名称空间,语法如下:

     import module1[,module2,[...moduleN]]

     import module as module_new

注:重新定义一个名称空间,module被替换,如果其它的模块名称重复,而不重新命名的话会覆盖其它的名称空间。

    from-import语句:

    常用于只导入指定模块的部分(或所有)属性至当前名称空间。语法如下:

    form module import name1[,name2[,...nameN]]

    说明:import和form都是隐式的赋值语句,import是将整个模块对象赋值给一个变量名(名称空间),from将一个或多个变量名赋值给导入此模块的模块中的同名对象。

例如:新建module1.py,以UTF-8编码格式保存

def printer(str1):

    print(str1)

案例:将整个模块对象赋值给一个变量名   

>>> import module1
>>> module1.printer('hello python')
hello python

注:也可以这么写:sys=__import__('sys'),还可以使用as重命名import语句扩展(as-重命名)

>>> import module1 as md1

>>> md1.printer('hello python')

hello python

2.2、from 语句

  将一个或多个变量名赋值给另一个模块中的同名对象。也就是把这个变量名导入到当前的作用域。

>>> from module1 import printer

>>> printer('hello python')

hello python

>>> from module1 import * #把模块中所有的变量名复制到当前作用域内

>>> printer('hello python')

hello python

    Python中的导入其实是运行时的运算。程序第一次导入指定文件时,会执行三个步骤:

    a)找到模块文件

        在指定的路径下搜索模块文件   

    b)编译成字节码(需要时)

        文件导入时就会编译,顶层的.pyc字节码文件在内部使用后会被丢弃,只有被导入的文件才会留下.pyc文件

    c)执行模块的代码来创建其所定义的对象

       模块文件中的所有语句都会依次执行,从头至尾,而此步骤中任何对变量的赋值运算,都会产生所得到的模块文件的属性。

注意1:import模块的搜索路径:主目录、pythonPath目录(如果设置了环境变量)、标准库目录、.pth文件中配置的目录(如果存在)。而这组成了sys.path,也就是模块的搜索路径。

例如:

>>> import sys

>>> sys.path

['', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python38\\Lib\\idlelib', 'C:\\Users\\Administrator\\AppData\......']

注:除了改变上面的路径外,sys.path返回的是一个列表,我们可以在列表中添加自定义搜索路径。

我在C:\mypython目录中新建一个moduleA.py文件,代码如下:

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

name='我是一个自定义目录里的模块'

def printer()

print(name)



>>> import moduleA

Traceback (most recent call last):

  File "<pyshell#0>", line 1, in <module>

    import moduleA

ModuleNotFoundError: No module named 'moduleA'

>>> sys.path.append('C:\mypython')

>>> sys.path

['', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python38\\Lib\\idlelib', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python38\\python38.zip', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python38\\DLLs', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python38\\lib', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python38', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python38\\lib\\site-packages', 'C:\\mypython']

>>> import moduleA

>>> moduleA.printer()

我是一个自定义目录里的模块

注意2:模块在第一次导入后,再次导入会跳过上面三个步骤,只提取内存中已加载的模块对象。如果想要再次导入的话使用reload函数。Reload函数载入并运行了文件最新版本的代码。

注意3:在python2.x中它是内置函数,直接调用就可以了,但是在python3.x中不是内置函数。python3.0把reload内置函数移到了imp标准库模块中。它仍然像以前一样重载文件,但是,必须导入它才能使用。

3、命名空间

    命名空间是用来储存变量名和对象绑定关系的,在 Python 中用字典来储存。命名空间存在的意义就是更好的管理名称,使得代码块之间的命名可以相同,却又不冲突,命名空间是运行时的运行环境决定的模块的命名空间可以通过属性__dict__或者dir(module)来获取(其实模块的名称就是一个名称空间)。命名空间一般可分为三种(局部命名空间->全局命名空间->内建命名空间):

    局部命名空间(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是),使用locals()获取。

    全局命名空间(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量,使用globals()获取。

    内建命名空间(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等,可以使用dir(__builtins__)查看。

    为了更好的管理变量,于是作用域就诞生了,作用域是可以直接访问到名称空间的文本区域。作用域必定是对某个对象内部而言的,一个函数内部、一个模块全局等。作用域是定义程序该如何搜索确切地“名字-对象”的名称空间的层级关系。作用域又可理解成权限,一块代码对哪些命名空间有权限。模块是一个独立的作用域。作用域有四种(本地作用域->闭合最重要->全局作用域->内建作用域)

    本地作用域(Local):最内层的函数(def或lambda)。

    闭合作用域(Enclosing):嵌套的父级函数的局部作用域,函数的上级函数的局部作用域。如果A函数内定义了一个B函数,那么相对B函数内的变量A函数内的变量处于闭合作用域。

    全局作用域(Global):最外部定义的变量。

    内建作用域(Built-in):内建模块内定义的函数与关键字。

    搜索变量的优先级顺序依次是:局部作用域>外层作用域>当前模块中的全局>python内置的作用域。(LEGB)

    Pyhton能够改变变量作用域的代码段是:模块(module),类(class)、函数(def/lambda)。其他代码块不会引入新的作用域。如:if/elif/else、try/except/finally、for/while并不能涉及变量作用域的更改。

     代码中变量名被赋值的位置,决定了该变量能被访问的范围,函数定义了局部(本地)作用域(局部变量),每次对函数的调用都创建了一个新的局部(本地)作用域。函数返回时,这个局部作用域就被销毁。

     而模块则定义了全局作用域(全局变量)。也就是说创建于模块文件顶层的变量具有全局作用域,对于外部访问就成了一个模块对象的属性。全局作用域的范围仅限于单个文件。当作用域被销毁时,所有保存在该作用域内的变量的值就被丢弃。

命名空间例如:

a = 1  # a 处在全局命名空间,赋值修改的是名称空间,而不是对象。这个赋值语句就是把a放入到了对应的命名空间,然后让它指向一个值为1的整数对象。
print(globals())  # 打印全局命名空间中的内容


def func():
    a = 2  # b 处在局部命名空间,#名称是a 对象是2
    print(locals())  # 打印局部命名空间内容


func()

print(__name__)  # __name__ 处在内建命名空间

# 内建命名空间:type、sum、abs
print(dir(__builtins__))

输出结果:

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000001D31910>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/pyDemo/test/moduleA.py', '__cached__': None, 'a': 1}
{'a': 2}
__main__
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException',......, 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']

分析:虽然在同一个模块中,但由于命名空间的不同,在全局模块中存在a,同样在局部命名空间中也可以存在a,他们互不受影响。

    func(),中如果想改变全局作用域中的变量a的值呢?关于作用域会涉及到两个关键字global关键字和nonlocal关键字

    如果想对内层的变量域中的代码想修改global中的变量值,使用global关键字。如果内层的变量域中的代码想修改enclosing中的变量值,使用nonlocal关键字。如果没有使用这两个关键字,对其进行修改,会生成局部变量进行赋值,并且在本作用域使用的时候会覆盖高层作用域的值,但是不影响高层作用域中的值。

例如:

>>> a=100

>>> def func01():

    print(a)

   a=200

>>> func01()

UnboundLocalError: local variable 'a' referenced before assignment

>>> a

100

解释:在预编译的时候,由于在func01()函数中对a进行了赋值,所以在函数这个作用域中的a被视为局部变量。局部变量的优先级高于全局变量。当打印a的时候,这个局部变量还没有被赋值。所以报错了。但是他的赋值并不影响外部全局变量的值。

例如:

>>> is_this_global='xyz'

>>> def func02():

    global is_this_global

    this_is_local = 'abc'

    is_this_global = 'def'

    print(is_this_global+this_is_local)

>>> func02()     

defabc

>>> is_this_global  #使用了global关键字,调用函数全局变量值被改变

'def'

例如:

>>> def func01():

    is_this_enclosing='xyz'

    def func02():

        nonlocal is_this_enclosing #使用nonlocal关键字

        this_is_local='abc'

        is_this_enclosing='def'

        print(this_is_local+is_this_enclosing)

    func02()

    print(is_this_enclosing)

>>> func01()

abcdef

def

4、包-Packages

    随着我们的应用程序规模越来越大,带有许多模块,我们将相似的模块放在一个包中,而将不同的模块放在不同的包中。这使项目(程序)易于管理且概念清晰。

    包是由一系列模块组成的集合。当不同作的模块进行按文件夹分类后再组成一个整体的库,可以称为包。包是用来组织模块的一个目录。 为了让Python将目录当做内容包,包导入语句的路径内的每个目录中必须包含__init__.py文件,用于标识当前文件夹是一个包。但通常__init__.py为空,仅用于扮演包初始化的挂钩、替目录产生命名空间以及使用目录导入时实现from * 行为的角色。但也可以设置__all__变量。如果没有__init__.py,则无法识别这是一个包。

    例如:对于Game包,下面有分为Sound、Image、Level包。

导包语法:

a)可以从包中导入单独的模块:

   import PackageA.SubPackageA.ModuleA,使用时必须用全路径名

b)可以直接使用模块名而不用加上包前缀

   from PackageA.SubPackageA import ModuleA

c)直接导入模块中的函数或变量

   from PackageA.SubPackageA.ModuleA import functionA

5、常用模块介绍

    python中内置了很多模块,模块分为三种:1)自定义模块;2)标准库(包含内置模块);3)开源模块;

    什么是标准库(内置模块),在Python官方的文档这里有说到:

    Python’s standard library is very extensive, offering a wide range of facilities as indicated by the long table of contents listed below. The library contains built-in modules (written in C) that provide access to system functionality such as file I/O that would otherwise be inaccessible to Python programmers, as well as modules written in Python that provide standardized solutions for many problems that occur in everyday programming。

    翻译:Python的标准库非常广泛,提供了各种各样的工具,如下面列出的长目录所示。该库包含内置模块(用C编写,但是也不全是用C),这些模块提供对系统功能的访问,如Python程序员无法访问的文件I/O,以及用Python编写的模块,这些模块为日常编程中出现的许多问题提供标准化的解决方案。

    所以在lib目录下,我们可以看到os.py,却看不到sys.py,原因就是它是操作系统相关,用C语言编写的。内置模块不是标准库,但是内置模块可以划分到标准库一类中去。大多数情况下,对它们之间没有做区分的必要。但是在理解Python的模块查找顺序时,这却是一个至关重要的差异。import寻找模块有两个步骤:

    1)搜索「内置模块」(built-in module)

    2)搜索 sys.path 中的路径

    而 sys.path 在初始化时,又会按照顺序添加以下路径:

    1)当前执行脚本文件所在目录;

    2)环境变量 PYTHONPATH中列出的目录(类似环境变量 PATH,由用户定义,默认为空);

    3)模块默认安装目录(通常是标准库)。

    查看python支持的标准库/模块:

#查看python支持的库/模块
>>> help('modules')
...

#查看python的内置模块
>>> import sys
>>> print(sys.builtin_module_names) #内置模块
('_abc', '_ast', '_bisect', '_blake2', '_codecs', '_codecs_cn', '_codecs_hk', '_codecs_iso2022', '_codecs_jp', '_codecs_kr', '_codecs_tw', '_collections', '_contextvars', '_csv', '_datetime', '_functools', '_heapq', '_imp', '_io', '_json', '_locale', '_lsprof', '_md5', '_multibytecodec', '_opcode', '_operator', '_pickle', '_random', '_sha1', '_sha256', '_sha3', '_sha512', '_signal', '_sre', '_stat', '_statistics', '_string', '_struct', '_symtable', '_thread', '_tracemalloc', '_warnings', '_weakref', '_winapi', '_xxsubinterpreters', 'array', 'atexit', 'audioop', 'binascii', 'builtins', 'cmath', 'errno', 'faulthandler', 'gc', 'itertools', 'marshal', 'math', 'mmap', 'msvcrt', 'nt', 'parser', 'sys', 'time', 'winreg', 'xxsubtype', 'zlib')

     使用python标准库/模块:

import module
from module.xx.xx import xx
from module.xx.xx import xx as rename  
from module.xx.xx import *

pip3 install 开源三方模块

    前面呢,我们也接触到了sys内置模块和os标准库,python中提供了很多这种的标准库/内置模块,常见的有:

5.1、time(内置模块) & datetime(标准库)

import time

time.localtime([secs]):将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。
time.time():返回当前时间的时间戳。
time.gmtime([secs]):和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。
time.mktime(t):将一个struct_time(UTC+8)转化为时间戳。
time.sleep(secs):线程推迟指定的时间运行。单位为秒。
time.asctime([t]):把一个表示时间的元组或者struct_time表示为这种形式:'Sun Jun 20 23:21:05 1993'。如果没有参数,将会将time.localtime()作为参数传入。
time.ctime([secs]):把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。
time.strftime(format[, t]):把一个代表时间的元组或者struct_time(如由time.localtime()和time.gmtime()返回)转化为格式化的时间字符串。
time.strptime(string[, format]):把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。
time.clock():这个需要注意,在不同的系统上含义不同。在UNIX系统上,它返回的是“进程时间”,它是用秒表示的浮点数(时间戳)。

import datetime

datetime.date.today() 本地日期对象,(用str函数可得到它的字面表示(2014-03-24))
datetime.date.isoformat(obj) 当前[年-月-日]字符串表示(2014-03-24)
datetime.date.fromtimestamp() 返回一个日期对象,参数是时间戳,返回 [年-月-日]
datetime.date.weekday(obj) 返回一个日期对象的星期数,周一是0
datetime.date.isoweekday(obj) 返回一个日期对象的星期数,周一是1
datetime.date.isocalendar(obj) 把日期对象返回一个带有年月日的元组
datetime对象:
datetime.datetime.today() 返回一个包含本地时间(含微秒数)的datetime对象 2014-03-24 23:31:50.419000
datetime.datetime.now([tz]) 返回指定时区的datetime对象 2014-03-24 23:31:50.419000
datetime.datetime.utcnow() 返回一个零时区的datetime对象
datetime.fromtimestamp(timestamp[,tz]) 按时间戳返回一个datetime对象,可指定时区,可用于strftime转换为日期表示 
datetime.utcfromtimestamp(timestamp) 按时间戳返回一个UTC-datetime对象
...

5.2、random(标准库)

random.random()#用于生成一个0到1的随机符点数: 0 <= n < 1.0
random.randint(a, b),用于生成一个指定范围内的整数。其中参数a是下限,参数b是上限,生成的随机数n: a <= n <= b
randrange([start], stop[, step]), # 从指定范围内,按指定基数递增的集合中 获取一个随机数。
random.choice(sequence)参数sequence表示一个有序类型。

5.3、os(标准库)

#提供对操作系统进行调用的接口
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir ("dirname") 改变当前脚本工作目录;相当于 shell下cd
os.curdir 返回当前目录: ('.')
os.pardir 获取当前目录的父目录字符串名:('..')
os.makedirs ('dirname1/dirname2') 可生成多层递归目录
os.removedirs ('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir ('dirname') 生成单级目录;相当于shell中mkdir dirname
os.rmdir ('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir ('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
...
前面已经写过

5.4、sys(内置模块)

sys.argv 命令行参数List,第一个元素是程序本身路径
sys.exit (n) 退出程序,正常退出时exit(0)
sys.version 获取 Python 解释程序的版本信息
sys.maxint 最大的 Int 值
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH 环境变量的值
sys.platform 返回操作系统平台名称

5.5、shutil(标准库)

#高级的 文件、文件夹、压缩包 处理模块

shutil.copyfileobj(fsrc, fdst[, length]) 将文件内容拷贝到另一个文件中,可以部分内容

shutil.copyfile(src, dst) 拷贝文件

shutil.copymode(src, dst) 仅拷贝权限。内容、组、用户均不变

shutil.copystat(src, dst) 拷贝状态的信息,包括:mode bits, atime, mtime, flags

shutil.copy(src, dst) 拷贝文件和权限

shutil.copy2(src, dst) 拷贝文件和状态信息

shutil.rmtree(path[, ignore_errors[, onerror]]) 递归的去删除文件

shutil.move(src, dst) 递归的去移动文件

...

5.6、json & pickle(标准库)

# 用于序列化的两个模块

#json,用于字符串 和 python数据类型间进行转换


#序列化

import json
info={
    'name':'鲁班',
    'age':22
}

f=open('test.txt','w')

f.write(json.dumps(info))#用于将Python数据以字符串的形式写入到文件中

f.close()

#反序列化
f = open('test.txt','r')

data=json.loads(f.read())#从文件中加载出Python的数据类型

print(data['age'])

# pickle,用于python特有的类型 和 python的数据类型间进行转换

#序列化
import  pickle
def sayhi(name):
    print("hello  python",name)

info = {
    'name':'鲁班',
    'age':22,
    'func':'sayhi'
}
f=open("pickle_test.txt",'rb')

pickle.dump(info,f)#==f.write(pickle.dumps(info))

f.close()

#反序列化
import pickle

f=open("pickle_test.txt",'rb')

data=pickle.load(f)
print(data["age"])

5.7、xml、yaml(标准库)

xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,以前,在json还没诞生的时候,大家只能选择用xml。

Python也可以很容易的处理ymal文档格式。

5.8、logging(标准库)

import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

第八章 对象和类

    面向过程:根据业务逻辑从上到下写垒代码。

    函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可。

    面向对象:对函数进行分类和封装,让开发更快更好更强。

    面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用。类就是一个模板,模板里可以包含多个函数,函数里实现一些功能。对象则是根据模板创建的实例,通过实例对象可以执行类中的函数。

一、类和对象的创建

1、语法及使用

# 创建类(class是关键字,表示类)
class className:
    # 创建类中的函数
    def Func(self):
        #do something

# 使用类创建对象
obj = className()

例如:

>>> class Person:
	def eat(self):
		print('eat fruit')

		
>>> obj = Person()
>>> obj.eat()
eat fruit

2、面向对象三大特性

    如果接触过java,那可能很快就会想到三大特性:封装、继承和多态。在python中也类似。

2.1、封装

    封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。

>>> class Person:
	def __init__(self,name,age): # self 是一个形式参数,类似于java中的this,当执行obj1 = Person('小明',18)时self就是obj1
		self.name = name
		self.age = age
	def printInfo(self):
		print(self.name,self.age)

		
>>> obj1 = Person('小明',18)
>>> obj1.name # 直接调用obj1对象的
'小明'
>>> obj1.age
18
>>> obj2 = Person('小红',18)
>>> obj2.printInfo()
小红 18
>>> 

2.2、继承

    面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。

>>> class Animal:
	def eat(self):
		print(self.name)
	def sleep(self):
		print(self.name,'睡觉')

		
>>> class Person(Animal):
	def __init__(self,name):
		self.name = name
	def think(self):
		print('思考中...')

		
>>> p1 = Person('小明')
>>> p1.eat()
小明
>>> p1.sleep()
小明 睡觉
>>> p1.think()
思考中...

    Java和C#中则只能继承一个类,但是Python的类可以继承多个类,Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先广度优先。前面我们也有提到过这个概念。

     Python 3.x中默认都是新式类,经典类被移除,没必要显式的继承object,Python 2.x中默认都是经典类,只有显式继承了object才是新式类。当类是经典类时,多继承情况下,会按照深度优先方式查找。当类是新式类时,多继承情况下,会按照广度优先方式查找。

2.3、多态

     Pyhon不支持Java和C#这一类强类型语言中多态的写法,但是可以模拟出多态。

class F1:
    pass


class S1(F1):

    def show(self):
        print 'S1.show'


class S2(F1):

    def show(self):
        print 'S2.show'

def Func(obj): #封装一个方法
    print obj.show()

s1_obj = S1()
Func(s1_obj) 

s2_obj = S2()
Func(s2_obj)

 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐