《简明python教程》笔记一
读《简明Python教程》笔记:
本书的官方网站是www.byteofpython.info
安装就不说了,网上很多,这里就记录下我在安装时的问题,首先到python官网下载,选好安装路径安装好后,一定要配置环境变量,详细呢可以看武老师的博客(我的python编程入门老师虽然他不认识我,我也不认识他)。
重要
在你的程序中合理地使用注释以解释一些重要的细节——这将有助于你的程序的读者轻松地理
解程序在干什么。记住,这个读者可能就是6个月以后的你!
可执行的python程序(linux下):
$ chmod a+x hello_world.py
$ ./hello_world.py
$ 输出程序的执行结果
chmod命令用来改变文件模式,给系统中所有用户这个源文件的执行权限,然后就可以直接通过指定源文件的位置来执行程序,使用./提示程序位于当前目录。
也可以把.py去掉直接执行文件,因为系统要使用源文件第一行指定的解释器来执行该文件。
只要知道文件的确切位置,你就可以运行程序——但是如果你希望你的程序可以从各个位置运行,你可以把你的程序保存在PATH环境变量中的目录之一,系统会自动在PATH中的目录里寻找你要执行的文件。
$echo $PATH
/opt/mono/bin/:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/swaroop/bin
$cp hello_world.py /home/swaroop/bin/hello_world
$hello_world
程序执行的结果
用echo命令显示PATH变量,用$给变量名加前缀以向shell表示我们需要这个变量的值。我们看到的/home/swaroop/bin是PATH变量中的目录之一。swaroop是在系统中使用的用户名。你可以把你选择的目录添加到PATH变量中——这可以通过运行PATH=$PATH :/home/swaroop/mydir完成。
当你想要在任何时间、任何地方运行你的程序,这个方法很有用。他就好像创造你自己的指令,如同cd或其他linux终端或DOS提示符命令那样。
提示:(这个问题困惑我好久)
对于Python,程序、脚本或者软件都是指同一个东西。
获取帮助
help(str)括号内是你要查询的数据类型。
linux下的操作:
如果想要获取关于如print那样操作符的帮助,那么你需要正确的设置PYTH ON DOCS环境变量。这可以在linux中轻松的通过env完成。
$ env PYRH ON DOCS=/usr/share/doc/python-docs-2.3.4/html/python
Python2.3.4(#1,0 ct26 2004,16:42:40)
[GCC 3.4.2 20041017(Red Hat3.4.2-6.fce)] on linux2
Type"help","copyright","cred its"or"license"form ore inform ation.
>>>help("print")
注意"print"要加引号。
一、字符串:
1、字符串:(字符串是字符的序列,是不可变的)
使用字符串的方式:
~ 单引号(’)
~ 双引号(”) #"what's your name?"双引号内使用单引号不用转义符
~ 三引号('''或""") #'''what's your name? My name is "Guido's admisers", I like python.'''三引号中自由的使用单引号和双引号
2、转义符:
'what\'s your name?'如果没有 \ python解释器则找不到字符串的起止位置。
\\ 表示 \ 的意思
”how old are you?\
what's your name?"
上面的字符串则表示:行末的单独的一个 \ 表示字符串在下一行继续,而不是开始新的一行。
3、自然字符串:
r'what\'s your name? \n My name is Guido?'
这样字符串里的转义符就不会进行转义处理了。
在处理正则表达式时一定要用"r"
二、变量:
1、变量名命名的规则:
~ 第一个字符必须是字母(大小写均可)或者一个下划线('_')
~ 其他部分可以由字母(大小写均可)、下划线('_')或树脂(0-9)组成
~ 相同的变量名是区分大小写的,例如name!=Name
~ 变量名中只能有以上说的方式内容组成
三、对象:
在Python中,在程序中用到的任何东西都叫对象。
四、逻辑行与物理行:
物理行是你在编写程序时说看见的。逻辑行是Python解释器看见的单个语句。如果在一个物理行使用多于一个逻辑行,就需要用分号(;)来特别标明这种用法。(;)表示一个逻辑行的结束。(尽量避免使用一个物理行存在多个逻辑行)
多个物理行可以写一个逻辑行,例如:
s = "This is a string.\
This continues the sting."
print(s)
执行输出:
This is a string.This continues the sting.
五、缩进:
在python中缩进决定语句的分组,同一层次的语句必须有相同的缩进,错误的缩进会引发错误。
在使用缩进时,空格和制表符不要混合使用,因为在跨平台操作时无法正常工作,在每个缩进层次使用单个制表符或者使用四个空格。
六、运算符与表达式:
运算符
运算符优先级
在运算中,python会优先计算下表中最下面的运算符,最好使用()圆括号来分组运算和操作数,使程序更加易读。
在下表中列在同一行的运算符具有相同优先级。
下表是一个优先级的默认顺序,如若想改变优先级的顺序,则需使用圆括号。
结合规律:
具有相同优先级的运算符按照从左向右的顺序计算。一些如赋值运算符那样的运算符是由右向左结合的,即a=b=c被处理为a=(b=c)。
七、控制流:
if语句
if条件为真,执行if下的语句;如果if条件为假,处理另一块elif语句;否则实行else块,else从句是可选的。
注意:if、elif、else语句在结尾处包含一个冒号——我们通过他告诉python下面跟着一个语句块。
#! usr/bin/env python # -*-coding:utf-8-*- name = input("what's your name?") if name == "VV": print("I love you!") elif name == "MM": print("Get out!") else: print("I don't know.")
while语句
如果条件为真,while语句允许重复执行一块语句。所以while语句是循环语句。同时,也有一个可选的else从句
#!/usr/bin/env python # -*- coding:utf -8-*- while 1>2: print(123) break else: print(789)
for循环
for...in...是另外一个循环语句,它在以序列的对象上递归即逐一使用队列中的每个项目。
#!/usr/bin/env python # -*- coding:utf -8-*- for i in range(1,5,2): print(i) else: print('MM')
range(1,5)生成序列[1,2,3,4],range的默认步长为1,给range提供第3个数,它将成为步长。例如:range(1,5,2)给出[1,3]。
else总是会在for循环结束后执行一次,除非遇到break
break语句:终止循环语句,一旦遇到立刻停止执行循环程序。
continue语句:终止后面的剩余语句,然后继续进行下一轮循环。
八、函数
定义函数:
#!/usr/bin/env python # -*- coding:utf -8-*- def name(): #定义函数 pass #函数体 name() #执行函数
函数的参数:
函数的参数有形式参数和实际参数
定义时圆括号内的参数为形式参数,执行时圆括号内的参数为实际参数。
局部变量:
当你在函数定义内声明变量的时候,它们与函数外具有相同名称的其他变量没有任何关系,即变量名称对于函数来说是局部的。这称为变量的作用域。所有变量的作用域是它们被定义的块,从他们的名称被定义的那点开始。
全局变量(global):
如果你想为一个定义在函数外的变量赋值,那么就得告诉python这个变量不是局部的,而是全局的。我们使用global语句完成这一功能。没有global语句是不可能为定义在函数外的变量赋值的。
#!/usr/bin/env python # -*- coding:utf -8-*- MM = "alex" def name(): global MM print(MM) name()
默认参数值:
你可以在函数定义的形参后加上赋值运算符(=)和默认值,从而给形参指定默认参数值。
默认参数值应该是一个不可变的参数。
#!/usr/bin/env python # -*- coding:utf -8-*- def name(MM, VV="Lily"): pass name('TT')
关键参数:
不再依照传入参数的顺序来分配参数,而是使用名字来参入参数。
这样做的两个优势:
~ 由于我们不必担心参数的顺序,使用函数变得更加简单。
~ 假设其他参数都有默认值,我们可以只给我们想要的那些参数赋值。
#!/usr/bin/env python # -*- coding:utf -8-*- def name(MM, NN, VV="Lily"): pass name(NN='pp', MM='TT')
return语句:
return语句用来从一个函数返回即天出函数。我们也可以选择从函数返回一个值。
函数一旦遇到return立刻终止函数的运行并返回其后的参数。
#!/usr/bin/env python # -*- coding:utf -8-*- def name(MM, VV="Lily"): if MM==VV: return MM else: return VV name('TT')
DocStrings:
奇妙的特性,文档字符串。DocStrings是一个重要的工具,他可以帮助你的程序文档更加简单易懂,你应该尽量使用它。甚至可以在程序运行的时候从函数恢复文档字符串!
#!/usr/bin/env python # -*- coding:utf -8-*- def printM_ax(x, y): '''Prints the m axim um of two num bers. The two values m ust be integers.''' x = int(x) # convert to integers, if possible y = int(y) if x > y: print(x, 'is m axim um ') else: print(y, 'is m axim um ') printM_ax(3, 5) print(printM_ax.__doc__) #执行结果 5 is m axim um Prints the m axim um of two num bers. The two values m ust be integers.
引用原文:
'''
~ 在函数的第一个逻辑行的字符串是这个函数的文档字符串 。注意,DocStrings也适用于模块和类,我们会在后面相应的章节学习它们。
~ 文档字符串的惯例是一个多行字符串,它的首行以大写字母开始,句号结尾。第二行是空行,从第三行开始是详细的描述。 强烈建议,在你的函数中使用文档字符串时遵循这个惯 例。
~ 你可以使用__doc__(注意双下划线)调用printM_ax函数的文档字符串属性(属于函数的名称)。请记住Python把每一样东西都作为对象,包括这个函数。我们会在后面的类一章学习更多关于对象的知识。
~ 如果你已经在Python中使用过help(),那么你已经看到过DocStings的使用了!它所做的只是抓取函数的__doc__属性,然后整洁地展示给你。你可以对上面这个函数尝试一下——只是在你的程序中包括help(printM_ax)。记住按q退出 help。
~ 自动化工具也可以以同样的方式从你的程序中提取文档。因此,我 强烈建议 你对你所写的任何正式函数编写文档字符串。随你的Python发行版附带的pydoc命令,与help()类似地使用D ocStrings。
'''
九、模块:
简介
模块就是一个包含了所有你定义的函数和变量的文件。为了在其他程序中重用模块,模块的文件名必须以.py为扩展名。
sys模块的使用:(sys是system的缩写)
示例:
#在Pycharm中运行
#filename:name.py
import sys print("The command line argum entsare:") for i in sys.argv: print(i) print("\n\nThe PYTHONPATH is", sys.path, "\n") #执行结果: The command line argum entsare: C:/Users/PycharmProjects/python(learning)/name.py The PYTHONPATH is ['C:\\Users\\PycharmProjects\\python(learning)', 'C:\\Users\\PycharmProjects\\python(learning)', 'C:\\Users\\Anaconda3\\python35.zip', 'C:\\Users\\Anaconda3\\DLLs', 'C:\\Users\\Anaconda3\\lib', 'C:\\Users\\Anaconda3', 'C:\\Users\\Anaconda3\\lib\\site-packages', 'C:\\Users\\Anaconda3\\lib\\site-packages\\Sphinx-1.4.1-py3.5.egg', 'C:\\Users\\Anaconda3\\lib\\site-packages\\win32', 'C:\\Users\\Anaconda3\\lib\\site-packages\\win32\\lib', 'C:\\Users\\Anaconda3\\lib\\site-packages\\Pythonwin', 'C:\\Users\\Anaconda3\\lib\\site-packages\\setuptools-23.0.0-py3.5.egg']
sys.argv变量是一个字符串的列表。sys.argv是包含了命令行参数的列表,即使用命令行传递给你的程序的参数。
(we are GG)跟在执行程序的后面作为参数传递给程序。python把把它存储在sys.argv变量中。
sys.path所列内容为python执行时自动搜寻的所有路径,如果被执行文件不再sys.path所列的路径内,在执行时必须把文件所在路径写入,可看下例:
#在终端命令行运行
python C:/Users/PycharmProjects/python(learning)/name.py we are GG #执行结果: The command line argum entsare: C:/Users/PycharmProjects/python(learning)/name.py we are GG The PYTHONPATH is ['C:\\Users\\PycharmProjects\\python(learning)', 'C:\\Users\\PycharmProjects\\python(learning)', 'C:\\Users\\Anaconda3\\python35.zip', 'C:\\Users\\Anaconda3\\DLLs', 'C:\\Users\\Anaconda3\\lib', 'C:\\Users\\Anaconda3', 'C:\\Users\\Anaconda3\\lib\\site-packages', 'C:\\Users\\Anaconda3\\lib\\site-packages\\Sphinx-1.4.1-py3.5.egg', 'C:\\Users\\Anaconda3\\lib\\site-packages\\win32', 'C:\\Users\\Anaconda3\\lib\\site-packages\\win32\\lib', 'C:\\Users\\Anaconda3\\lib\\site-packages\\Pythonwin', 'C:\\Users\\Anaconda3\\lib\\site-packages\\setuptools-23.0.0-py3.5.egg']
首先,使用import语句导入sys模块。
当python执行import sys语句的时候,它在sys.path变量中所列目录中寻找sys.py模块。找到后这个模块的主块中的语句将被执行,然后就可以使用模块。注意,初始化过程仅在我们第一次输入模块的时候进行。
要注意的是,脚本的名称总是sys.argv列表的第一个参数。所以,在这里,name.py是sys.argv[0]、we是sys.argv[1]......
.pyc文件
就是python为了加快模块的导入而创建的字节编译文件,这些文件就是以.pyc为扩展名。但你在下次从别的程序输入这个模块的时候,.pyc文件是十分有用的——它会快得多,因为一部分输入模块所需的处理已经完成。另外,这些字节编译的文件于是与平台无关的。
from...import...语句
详细内容:http://www.cnblogs.com/Guido-admirers/p/6085657.html
__name__模块
每个模块都有一个名称,在模块中可以通过语句找出模块的名称。这在一个场合特别的有用——当一个模块没第一次输入的时候,这个模块的主块将被运行。假如我们只想在程序本身被使用时运行主块,而在它被别的模块输入的时候不运行主块,就要用到__name__属性来完成。
示例:
#filename:name.py if __name__ == '__main__': print('This program is being run by itself') else: print('I an being imported from another module') #在命令行终端执行: $python name.py This program is being run by itself $python >>>import name I an being imported from another module >>>
在Python中每个模块都有它的__name__,如果它是'__main__',这说明这个模块被用户单独运行,我们可以进行相应的恰当操作。
dir函数
查看模块的属性生成一个属性列表。
十、数据结构:
列表(list)
list是处理一组有序项目的数据结构,列表的创建(一个空列表)li=[]。列表是可变的数据类型,可以对列表进行添加、删除或是搜索列表中的项目等的操作。
列表的操作方式与列表存在的方法:http://www.cnblogs.com/Guido-admirers/p/6124572.html
元祖(tuple)
元祖与列表相似,只是元祖是不可变的数据类型,所以列表有的方法元祖很多都没有。
元祖的方法操作:http://www.cnblogs.com/Guido-admirers/p/6124616.html
含有0个或1个项目的元祖。一个空的元祖由一对空的圆括号组成,如tu=(),然而含单个元素的元祖必须在第一(唯一一个)项目后跟一个逗号,这样python才能区分元祖和表达式中一个带圆括号的对象,tp=(2,)是只包含2的一个元素的元祖。
元祖最常用的的用法是用在打印语句中:
age = 22 name = 'guido' print('%s is %d years old'%(name, age)) print('Why is %s playing with that python?'%name) #执行结果: guido is 22 years old Why is guido playing with that python?
字典(dict)
字典的组成是由键值对组成,键必须是唯一的,而且键只能使用不可变的对象(比如字符串),基本说,应该只使用简单的对象作为键。
字典的使用及方法:http://www.cnblogs.com/Guido-admirers/p/6124623.html
序列
列表、元祖和字符串都是序列。序列的两个主要特点是索引操作符和切片操作符。索引操作符让我们可以从序列中抓取一个特定项目。切片操作符让我们能够获取序列的一个切片,即一部分序列。
引用
当你创建一个对象并给它赋一个变量的时候。这个变量仅仅引用那个对象,而不是表示这个对象本身!也就是说变量名指向你计算机中存储那个对象的内存。这被称作名称到对象的绑定。
示例(对象与引用):
print('Simple Assignment') shoplist = ['apple', 'mango', 'carrot', 'banana'] mylist = shoplist del shoplist[0] print('shoplist is',shoplist) print('mylist is',mylist) print("****************") print('Copy by making a full slice') mylist = shoplist[:] del mylist[0] print("****************") print('shoplist is', shoplist) print('mylist is', mylist) #执行结果: Simple Assignment shoplist is ['mango', 'carrot', 'banana'] mylist is ['mango', 'carrot', 'banana'] **************** Copy by making a full slice **************** shoplist is ['mango', 'carrot', 'banana'] mylist is ['carrot', 'banana']
注意:如果你想要复制一个列表或者类似的序列或者其他复杂的对象(不是如整数那样简单的对象),那么你必须使用切片操作符来取得拷贝。如果你只是想要使用另一个变量名,两个名称都引用同一个对象,那么如果你不小心的话,可能会引来各种麻烦。
解决问题——编写一个Python脚本
问题:我想要一个可以为我的所有重要文件创建备份的程序。
问题分析:尽管这是一个简单的问题,但是问题本身并没有给我们足够的信息来解决它。进一步的分析是必须的。例如,我们如何确定该备份哪些文件?备份保存在哪里?我们怎么样存储备份?
解决方法一:
首先声明这个方法只是千百种方法中的一种,每个人设计的方法都不尽相同。
1、需要备份的文件和目录由一个列表指定。
2、备份应该保存在主备份目录中。
3、文件备份成一个zip文件。
4、zip存档的名称是当前的日期和时间。
5、我们使用标准的zip命令,它通常默认的随linux发行版本提供。Windows用户可以使用Info-Zip程序。注意的是你可以使用任何的存档命令,只要他有命令行界面就可以了,那样的话我们可以从我们的脚本中传递参数给它。
import os import time source = ['/home/swaroop/byte', '/home/swaroop/bin'] target_dir = "/mnt/e/backup/" target = target_dir+time.strftime('%Y %m %d %h %M %S')+'.zip' #利用time的strftime方法列出目前的时间 # print(target) zip_command = "zip -qr '%s' %s" % (target, ''.join(source)) #'%s'%s是为了给%s格式化的内容加引号,编辑字符串的格式。 # print(zip_command) if os.system(zip_command) == 0: #直接在shell命令下运行zip_command字符串所代表的命令 print("Successfulbackup to", target) else: print("Backup FAILED")
注释:
time.strftime()括号内的内容%Y代表无世纪的年份,%m代表01—12的十进制月分数,其他依次类推。time模块的更多方法http://www.cnblogs.com/Guido-admirers/p/6085657.html
zip命令有一些选项和参数。-q要用来表示zip命令安静的工作。-r表示zip命令对目录递归的工作,即它包含子目录以及子目录中的文件。两个选项可以组合成缩写-qr。选项后面跟着待创建的zip归档的名称,然后再是待备份的文件和目录列表。.join地方法把source列表转换为字符串。
os.system函数就好像在系统中运行命令——运行成功,则返回0,否则它返回错误信号。
基于windows用户:
可以把source列表和target目录设置成任何文件和目录名,但是要小心windows把反斜杠(\)作为目录分隔符,而python用反斜杠表示转义符! 所以要使用自然字符串(r"string")
上面的程序可以正确的工作,但是(通常)第一个程序并不是与你所期望的完全一样。例如,可能有些问题你没有设计恰当,又或者你在输入代码时发生了一点错误,等等。正常情况下,你应该回到设计环节或者调试程序。
解决方法二:
我们可以对它做一些优化以便让它在我们的日常生活中变得更好。这称为软件的维护环节。
优化之一是采用更好的文件名机制——使用时间作为文件名,而当前的日期作为目录名,存放在主目录中。这样做的一个优势是你的备份会以等级结构存储,跟容易管理。另一个优势是文件名可以变短。还有一个优势是采用各自独立的文件夹可以帮助你方便的检查是否每天创建了备份,因为只有创建了备份,才会出现那天的记录。
import os import time source = ['/home/swaroop/byte', '/home/swaroop/bin'] target_dir = "/mnt/e/backup/" today = target_dir + time.strftime("%Y%m%d") now = time.strftime("%H %M %S") if not os.path.exists(today): #os.exists函数检验在主备份目录中是否有以当前日期作为名称的目录 os.mkdir(today) print("Successfully created directory", today) target = today + os.sep + now + ".zip" #os.sep变量会根据你的操作系统给出目录分隔符 # print(target) zip_command = "zip -qr '%s' %s" % (target, ''.join(source)) #'%s'%s是为了给%s格式化的内容加引号,编辑字符串的格式。 # print(zip_command) if os.system(zip_command) == 0: #直接在shell命令下运行zip_command字符串所代表的命令 print("Successfulbackup to", target) else: print("Backup FAILED")
os.sep:在Linux、Unix下它是'/',在windows下它是'\\',而在MacOS下它是':'。使用os.sep而非直接使用字符,会使我们的程序具有可移植性,可以在上述系统下工作。
解决方法三:
可以对每个归档名进行自定义输入标记。
import os import time source = ['/home/swaroop/byte', '/home/swaroop/bin'] target_dir = "/mnt/e/backup/" today = target_dir + time.strftime("%Y%m%d") now = time.strftime("%H %M %S") comment = input("Enter a comment-->") if len(comment) == 0: #以用户输入的字符长度是否为0,来判断用户是否有输入内容 target = today + os.sep + now + '.zip' else: target = today + os.sep + now + "_" + \ #同一逻辑行不同物理行,一定要加”\“反斜杠链接 comment.replace('', '_') + '.zip' #replace替换 if not os.path.exists(today): #os.exists函数检验在主备份目录中是否有以当前日期作为名称的目录 os.mkdir(today) print("Successfully created directory", today) zip_command = "zip -qr '%s' %s" % (target, ''.join(source)) #'%s'%s是为了给%s格式化的内容加引号,编辑字符串的格式。 # print(zip_command) if os.system(zip_command) == 0: #直接在shell命令下运行zip_command字符串所代表的命令 print("Successfulbackup to", target) else: print("Backup FAILED")
最理想的创建方法是使用zipfile和tarfile,是python的标准库。
软件的开发过程:
1、什么(分析)
2、如何(设计)
3、编写(实施)
4、测试(测试与调试)
5、使用(实施和开发)
6、维护(优化)
重要的:
我们创建这个备份脚本的过程是编写程序的推荐方法——进行分析与设计。开始是实施一个简单的版本。对它进行测试与调试。使用它以确信它如预期那样的工作。再增加任何你想要的
特性,根据需要一次次的重复这个编写—测试—使用的周期。记住软件是长出来的,而不是建造的。