老男孩视频教程前四期整理
前言
学习python已经有些时日了,初时接触从某大神的博客开始看起,搭配环境,陆陆续续跟着敲着代码,算是熟悉了。然而,初时学python还是好奇的因素比较多,一些细节虽然当时能懂,过了近一年,也便淡忘,甚而之前做的一些注释,慢慢地也不解其意,总结有以下几点原因:
- 学的时候不能说不专心,只是一些侧重点没有特别注意,太依赖于大神写的博客,对python的知识不能系统的全局通观;
- 缺少总结,学到的知识只能成为一盘散沙,形不成一个体系,以致慢慢遗忘;
- 缺少编程的锻炼,拷贝大神的代码抑或自己照着敲代码,终究不是自己的思维,缺少项目的历练,没有练习,没法融会贯通。
所以,在这次学习python老男孩的视频培训课程,一是温习或者说“预习”之前学习的python知识,心里有点数,稍全面的理解;二是了解python究竟重点需要掌握的是什么,应该从哪些地方勤加历练,工作时注重哪些部分;三是了解现实的开发环境和状态是怎样的,脱离语言学习的实验室状态。
此次python的学习整理,将重点参考老男孩的视频教程,辅以之前大神博客的学习随笔和之前的一些理解,了解哪些是新的,哪些是之前学习的,去年和今年的python学习内容有多少异同,试图能在脑海中形成一个体系,循着这个体系尝试编程锻炼,不断地反馈出自己对python的理解。
Python教程前四天总结
第一天:
这一天的课程主要是介绍了python的由来和发展,安装和环境准备,数据类型和运算,Unicode编码,导入模块,用户交互和格式化输出,循环控制和中断等内容。
- python版本的一些问题,python的版本目前有两类:2.x和3.x,而2.x版本不一定比某些3.x版本低,因为在稍后的一些2.x版本出来之前,python的3.x版本就出现了,目前稍新一点的python2.x版本是兼容3.x的,更为重要的是,目前linux的一些发行版本基本都是python2.x的,所以说现在目前使用较为广泛的还是python2.x,其中ubuntu系统的python版本一直是较新的,能够导入的模块也更全一些,截至笔者写这篇笔记,最新的稳定版本是2.11.
- python的声明变量:python的变量不需要声明,可以直接输入,数据类型是python自动决定
- 数据运算,乘方a**b,即a的b次方
- Python的缩进:python语言的一个很明显的特征就是强制缩进,因为没有类似于C语言和JAVA等通过各种括号包裹各种模块的机制,一般是“四个空格”的缩进,其实利用IDE(Intergrated Development Environment,集成开放环境)工作更加方便。
- 循环控制,其中在python中,循环可以有以下的用法
for a in range(10):
print a**2
这样就省却了其他语言类似加入一个i变量,递增循环
continue:跳过本次执行,继续下一次执行;
break:满足条件,整个循环停止
- 格式化输出和用户交互:raw_input,接受用户输入的字符串信息;input,接受用户输入的数字信息。格式化输出,如以下代码:
name = raw_input('please input your name:')
age = input('age:')
job = raw_input('Job:')
salary = raw_input('Salary:')
print '''
Personal information of %s:
Name : %s
Age : %s
Job : %s
Salary: %s
''' %(name,name,age,job,salary)
- 注释:python的单行注释:在句首加上#符号,pydev沿用eclipse加注释的方法,即ctrl+/的形式;多行注释,通过一对’’’添加。
- 使用和导入模块:from myMudule import myDef,即导入myMudule模块的myDef方法。
- 编码方式,unicode转为utf-8:enclde;utf-8转为unicode:decode,将py文件设为utf-8格式,#coding:utf-8 utf-8的编码方式是该文本下的ASCII字符依然是一个字节,非ASCII是2字节
这一天的学习的只是一些基础,但是要能真正的掌握理解,需要一直勤于练习。
第二天:
这一天的课程主要包括文件的处理及file的方法,字符串、列表、元组、字典、集合等的处理和相应的方法。
- file的几种文件处理模式,r只读,w只写,a追加,r+b以读写模式打开,w+b以写读模式打开,a+b以追加及读模式打开,b是以binary形式打开的意思,一般这样采用,一个例子:
f = file('D:\myFile.txt','r')
for line in f.readlines():
line = line.strip('\n').split(':')
print line
其中strip('\n')即去除换行符,以”:”作为分隔符,以序列的形式输出
- file的几种方法:flush()强制刷新:即不用关闭文件,更新文本文件;seek():跳转到想要跳转到的位置,tell()告知目前读取文件的所在位置;xreadlines()返回一个迭代器,相较于readlines()更高效,是读取一行,内存存储一行,再显示出来,而readlines()是读取全文内容,再显示出来。(实际是xreadline()内部有一个yield机制)
- 字符串方法,find(substring,[start[,end]])在可指范围内查找字串,返回索引值;count返回找到子串的个数;split(str,’’)将string转为list,以空格切分;join(list,’’)将list转为string,以空格连接
- 列表与其他语言中的数组类似,f1 = [3,5,2,5],扩展append(),insert(index,object):从某一处添加对象进去,remove()删除,index()某一元素的索引,pop()删除最后一个,f1[2:5],返回index从2到5,不包括5,即“顾头不顾尾”,[-5:]最后5个,[:5]前5个,[1::3],从index=1开始,每3个取一个
- tuple是如f2 = (1,2,3,2,3)的形式,只是元组的元素不能被修改;
- 字典,以key和value保存 如dic = { ‘name’:’focky’,’age’:23,’lily’:34},里面的元素是无序的,只能通过key来引用,词典的常用方法:dic.items():以列表的形式显示字典,两种读取字典的方式:
(1) for k,v in dic.items():
print k,v
(2) for i in dic:
print i,dic[i]
第二种效率更高,因为第一种还有一个转换成列表的过程
根据key获取value:直接dic[‘name’] = ‘focky’
setdefault(),dictc3.setdefault('fuck',6):如fuck这个字段在字典中不存在,将默认赋给一个6的值
update()合并字典
浅复制,copy(),字典中如果存在列表,执行copy()方法后,虽然不同步更新列表的一些记录,但是里面的列表时通过更新的,而深复制,里面的内容是完全独立更新的。字典一般占用的内存大一点,因为它需要维护一个hash表
- 集合,一般写作如name_set = {1,2,4,5},集合取交集:x&y,取差集:x-y,对称差集:x^y
- tab补全的一段代码:
try:
import readline
except ImportError:
print (“module readline not available”)
else:
import rlcompleter
readline.parse_and_bind(“tab:complete”)
这一天主要是几种数据类型的介绍方法等,平时要注意与其他语言相似数据类型的区别和相似点。
第三天:
这一天的内容主要包括pydev,python的IDE的用法,函数的用法,yield的使用,几种内置函数及其使用,random生成验证码,MD5加密。正则表达式等内容,重点是函数的概念。
- pydev的搭建:
(1)首先下载最新的python版本并在主机上安装,并在环境变量上Path系统变量加上python安装的具体路径;
(2)其次,下载eclipse,随便哪一个版本,可以下载java版本的,如果本机上没有安装jdk1.7及其以上版本,需要下载jdk并安装,安装完jdk后,需打开windows+R,输入cmd进入dos输出框:
出现上述字样,即代表jdk安装成功,如果不出现,需在系统变量设置(计算机-属性-高级系统配置-环境变量,添加如下内容:
创建JAVA_HOME变量,将jdk安装的具体路径添加至该变量上;
在系统变量里面的path下添加%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;前面如果没有‘;’符号,需要在前面添加该符号;
创建CLASSPATH变量,添加如下内容.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar。
出现上图内容,即代表创建成功。
配置一个interpreter,即pydev基于的python环境。
- 重要的__init__.py文件,当创建一个python package的时候,默认创建一个__init__.py文件,如果其他模块想调用该package里面的函数等,需要这一文件,删除这一文件,这个package就会变成一个文件夹,不能被其他模块调用。
- 是否为主文件调用:每个py文件都有一个__name__值,该值表示py文件被当前的主文件调用还是其他文件调用,如果被当前主文件调用,则该值为__main__;如果被其他文件调用,则显示相应模块下的py文件路径。所以一个py文件中如果存在“if __name__==__main__”,则该判断模块下的语句在该py文件被其他py文件调用时将不会执行。
- __file__:该py文件的具体路径;__doc__该文件创建时添加的说明注释。
- 默认参数和可变参数:默认参数,在定义函数里面的参数设置默认值。可变参数,参数前面加*号,def show(*arg),调用函数时参数的数量可变,调用函数时可以传入列表,然后以show(*sequence)的形式传入。字典可变参数:如:
def show(**kargs):
for item in kargs.items():
print item
show(name="woca",age='dd',hh='df')或者user_dict={ name="woca",age='dd',hh='df},
show(**dict)
可传入可变变量和对应的参数。
- yield的使用:yield即python的生成器。生成器的编写方法和函数定义类似,只是在return的地方改为yield。生成器中可以有多个yield。当生成器遇到一个yield时,会暂停运行生成器,返回yield后面的值。当再次调用生成器的时候,会从刚才暂停的地方继续运行,直到下一个yield。生成器自身又构成一个循环器,每次循环使用一个yield返回的值。
如下面的一个MyReadlines()方法即是xreadlines()的主要原理:
def MyReadlines():
seek = 0
while True:
with open('D:/temp.txt','r') as f:
f.seek(seek)
data = f.readline()
if data:
seek = f.tell()
yield data
else:
return
for item in MyReadlines():
print item
这样即是实现了逐行读取数据,逐行读入内存,然后显示出来。通过加断点,debug状态下运行可以更清楚的看到这种现象。
- lambda表达式(也作匿名函数)
缩略函数:
temp = lambda x,y:x+y
print temp(4,4)
- 几种内置函数:
dir(a),得出对象a的几种方法;
var(a),a的更详尽的几个信息,包括注释、路径等;
reload()重新导入模块,因为无论写多少from file import demo类似字样,最终只会导入一次;
divmod(x,y):得到商和余数;
pow():乘方;
all():全为非0,则为True;
any():任意有非0,则为True;
enumerate():得出带编号的循环,以元组的形式存储;
格式化输出:s=’ i am {0},{1}’ print s.format(‘alex’,’xxx’);
map(),re = map((lambda x: x+3),[1,3,5,6]),将函数对象依次作用于表的每一个元素;
filter():以过滤函数的形式过滤表里面的元素,返回一个经过过滤后的表;
reduce():累进的将函数作用于各个参数。reduce((lambda x,y: x+y),[1,2,5,7,9]);
zip():多个等长的序列,每次循环时从各个序列分别取出一个元素。
ta = [1,2,3]
tb = [9,8,7]
tc = ['a','b','c']
for (a,b,c) in zip(ta,tb,tc):
print(a,b,c)
得出如下的结果:
(1, 9, 'a')
(2, 8, 'b')
(3, 7, 'c')
eval():运行字符串里面的运算或者实现字符串里面所要实现的东西
- 反射:字符串形式导入模块,字符串形式执行函数。
temp = 'mysqlHelper'
func = 'count'
model = __import__(temp)
Function = getattr(model, func)
- 生成验证码的方法:
import random
code = []
for i in range(6):
if i == random.randint(1,5):
code.append(str(random.randint(1,5)))#这里有个列表转为字符串的强制转换
else:
temp = random.randint(65,90)
code.append(chr(temp))
print ''.join(code)
randint:随机产生整数,可设置范围,chr(temp)以数字作为序号,生成所对应的ASCII码,这里对应的是字母。这里有个字符串函数join,将列表的内容逐次添加到字符串中。
- MD5加密:这里有个常规开头:
import hashlib
hash = hashlib.md5()
hash.update('admin')
print hash.hexdigest()
- 序列化:
import pickle
li = ['nima',23,'shabi',666]
dumpsed = pickle.dumps(li)
print dumpsed
以python特有的文本形式来生成对应的文本流;
loadsed = pickle.loads(dumpsed)
print loadsed
返回文本流导出来的原列表
pickle.dump(li, open('D:/temp.pk','w'))
result = pickle.load(open('D:/temp.pk','r'))
print result
加工文件,生成文本流。
- json
json式的序列化更加普遍,而pickle序列化后得出的文本流只有python可以读取。如下面的代码得出的结果是:
import json
serialized_obj = json.dumps(li)
print serialized_obj
print type(serialized_obj)
normal_obj = json.loads(serialized_obj)
print normal_obj
print type(normal_obj)
结果:
["nima", 23, "shabi", 666]
<type 'str'>
[u'nima', 23, u'shabi', 666]
<type 'list'>
加工文件,生成文本流,将dumps()方法改为dump()方法
- 正则表达式
d:数字,+:>=1;
w:字母或者‘|’,‘_’;
*:>=0;
?:0或1;
{m}出现次数;
{m,n}出现次数[m,n]
‘?:’ 连续匹配
正则表达式在python中属于re模块,有search(),match(),findall()方法,match与search的区别是match从头开始匹配,开头如果没有就直接返回None,search则是发现匹配为止,findall()则是查找所有匹配项。具体调用如:
result1 = re.search('(\d+)\w*(\d+)', 'aaaa2345fgd45566'),匹配后的result1是一个对象,通过group()方法分组返回匹配的字符串。
匹配ip地址:print re.findall('(?:\d{1,3}\.){3}\d{1,3}',ip)
- time模块
print time.time():显示当前时间的时间戳,从1970年1月1日零点开始经过的秒数
print time.gmtime()
print time.localtime() #返回出time.struct_time(tm_year=2016, tm_mon=4, tm_mday=28, tm_hour=6, tm_min=48, tm_sec=32, tm_wday=3, tm_yday=119, tm_isdst=0)
time.struct_time(tm_year=2016, tm_mon=4, tm_mday=28, tm_hour=14, tm_min=48, tm_sec=32, tm_wday=3, tm_yday=119, tm_isdst=0)
print time.strftime('%Y-%m-%d %H:%M:%S'),格式化输出时间
这一天介绍了多种方法,内置函数,一些常见功能的代码实现。
第四天:
这一天开始具体讲面向对象的概念,一个对象所拥有的一些特殊方法,装饰器的概念,异常处理等。
- 反射机制:解析如一些网页地址对应方法:
data = raw_input('请输入地址:')
array = data.split('/')
userspace = __import__('backend.'+array[0])
model = getattr(userspace, array[0])
func = getattr(model, array[1])
func()
上述代码实现的就是输入网址,以/分割,调用某个模块下的某个方法。特殊方法getattr()是查询即时生成的属性。
- 装饰器
装饰器可以对一个函数、方法或者类进行加工,起到一个提高程序的重复利用性,增加程序的可读性等:
如下面的代码:
def outer(fun):
def wrapper(arg):
print '验证'
fun(arg)
return wrapper
@outer #装饰器
def Func1(arg):
print 'func1',arg
Func1('alex')
检测到这个装饰器,先执行装饰器对应的函数的内容,根据装饰器的内容对函数进行操作。
- 面向对象
视频教程老师说的一段话我觉得很有道理,面向对象说起来,大家都道听途说;讲起来,大家都以现实中的某些具体事物来类比。然而真正做开发了,很多可以抽象,可以通过面向对象的方式来解决的,多数人却不易想到,所以,真正理解面向对象,需要多做相关方面的编程,才能逐步培养意识。
python建立类的代码如下:
class Province(object):
#静态字段
memo = '中国的23个省之一'
def __init__(self,name,capital,leader,flag):
self.Name = name
self.Capital = capital
self.Leader = leader
#私有字段
self.__Thailand = flag
def sports_meet(self):
print self.Name + '正在开运动会'
这里面,Province是一个类,__init__是类的构造方法,实例化一个对象,必须有构造方法,其中的self变量相似于java的’this’,只是java是一个完全的面向对象语言,不需要赋有this这一变量,而python因为一些历史原因,综合了面向对象和函数式编程,一些语言的差别也来于此,理解这一点,才能明白与其他语言相关语法不同的缘由所在。类的非静态方法都需要self这一变量。
静态字段:静态字段是指直接在类体中定义,通过类.字段进行访问的;
静态方法:
@staticmethod
def Foo():
print '反腐'
即在方法上加上一个@staticmethod的装饰器,即代表是静态方法,这一语法也是与java等面向对象语言的折中选择,因为python不同于java等语言,在定义函数或者字段时,在之前就加上类型等信息,python是自动识别类型的,这是它的特点,而静态方法又必须在之前加上标识,所以就出现了这种装饰器来修饰的情况。
特性的概念:
@property
def Bar(self):
return 'nothing'
定义一个类方法,加上property装饰器,则在类的方法调用的时候将不以方法的形式调用,而是以字段的形式调用
私有方法:
def __sha(self):
print '逗比'
私有字段:
self.__Thailand = flag
即在前面加上__代表其为私有方法或者字段,不同于java等语言私有属性和方法不能被类外调用,python可以采取一种方法,使得可以访问类的私有属性或者方法。
@Thailand.setter
def Thailand(self,value):
self.__Thailand = value
通过这个特性的方式,使得;类外可以访问,但是既然是静态的方法,理论上还是不要进行类外的访问,python这样的设计,其实还是属于历史的折中。
析构函数:回收赋给类对象的内存空间,当该对象执行完所有的方法,调用所有的属性之后,将会执行析构方法,具体如:
def __del__(self):
print 'game over'
__call__()方法:一般类的方法的调用时是对象.方法(),而call方法直接是对象()就可以了。
继承:同其他面向对象式的语言一样,python继承的概念也是类似的。继承父类的方法,重写父类的方法。子类调用父类的方法,有两种方式,如调用父类的构造方法;
Father.__init__(self)
super(Son,self).__init__()
经典类和新式类的区别:以上创建类的时候,即使是父类,都是继承object
- 异常的处理
python的异常处理同其他语言(如JAVA类似),基本语法如下:
try:
except xxError,e:
except Exception,e:
else:
finally:(finally后面语句无论异常执行与否,都将执行)
自定义异常:
class MyException(Exception):
def __init__(self,msg):
self.error = msg
# print输出类的相关信息
def __str__(self,*args,**kwargs):
return self.error
obj = MyException('错误')
print obj
这样就定义了一个自定义异常。
raise exception的作用:当我们写如下的操作时:
def Validate(name,pwd):
if name == 'alex' and pwd == '123':
return True
else:
return False
try:
res = Validate('alex', '456')
if res:
print 'success'
else:
# print 'Error'
# 节省代码
raise Exception('Error')
except Exception,e:
print e
print 'database'
打印错误时,可能之后还要进行其他的操作,如上述的打印信息,或者回归到某页面,多个错误可能会归于到一个页面,这样可能节省代码。
这一天主要介绍的是面向对象的思想,要注意与其他面向对象语言的异同。