前言
1. virtualenv的使用
virtualenv做用是并行管理多个python程序,解决因多个python版本不兼容的问题
使用方法以下
1)安装pip: apt install pip
2)安装virtualenv:pip install virtualenv
3)创建工做目录:virtualenv test1
4)在工做目录下安装文件:cd test1, source bin/activate, pip install tornado
2. 推荐参考书
1)程序员的数学
2)大话数据结构,大话设计模式(后期再看)
3)C语言
4)python标准库
5) python基础教程
一,函数
进阶篇 函数 第一节
1.函数基本概念
注意点:
a: 输出函数时要加小括号
b: 函数中的return语句很是重要
c: 函数体为空的话,这里要写一个pass
def func_name():
pass# 函数体为空的话,这里要写一个pass,若是不写,函数是不成立的,
输出函数时要加小括号
def func1():
return "hello,world"
print func1()
错误例子1
print "a>b" if a>b else pass 执行的时候会报错,其实这个三元表达式是执行2个命令,print 和后面的条件语句,若是a>b 会执行print "a>b", 不然,会执行print pass,可是这个pass是一个命令体中的语句,结果就会报错,最好写成以下
if a>b:
print "a>b"
else:
pass
错误例子2
def func2():
print 123
test = func2()
print type(test)
输出结果是nonetype,因此函数中的return语句很是重要。
2.参数 <=> 抽象
例如
def add(num1,num2):
return num1+num2
print add(1,3)
print add(3,8)
3.参数分为可选参数,必选参数
1)计算不定数量的整数相加
def add(*num): #这里*会把num定义为一个tuple类型,2个*会定义为字典类型
d = 0
for i in num:
d += i
return d
print add(1,2,3,4,5)
print add(1,2,3)
print add(2,4,6,8,1,2,3,4,12312,12314,123,123,123)
2)可选和必选语法上的区别
1.可选参数 是有默认值的
2.必须参数 是没有默认值的
默认值和没有默认值的区别在于 “=”
例如
def add(num1,num2=4)
return num1+num2
print add(1)
若是参数中的"=4"没有的话,调用add函数的时候就须要写2个参数,若是定义函数的时候,2个参数都有等号,那么调用的时候直接用print add()就行
3) 函数的健壮性--考虑到大部分结果,并获得应急反馈处理。
1)各类状况下会返回什么东西(异常处理,条件判断)
2)自定义你想要的返回结果
def add(num1 ,num2):
if isinstance(num1,int) and isinstance(num2, int):
return num1+num2
else:
return '参数里有不是数字的类型'
print add('a',(1,2,3))
print add(1,2)
测试方法,断言
assert add(1,2) == 3
assert add(2,4) == 3
在这里,若是断言正确,不会输出任何信息,若是断言错误,就会返回AssertionError
二,函数第2节
1.元组,list,字典都能迭代,int和string不能迭代
2. 怎么去学习使用函数
(1)别管那么多复杂的,先直接把功能实现了。
(2)抽象成函数:命名规范,伪代码,参数默认值。
(3)将函数变得更健壮,让它能够跑不少地方
1.假设你写的函数是要交给你的基友用 -》 功能完整
2.假设你写的函数是要交给你的学弟用 -》 异常处理完善
(4) 测试
1.assert
2.对函数的返回进行一个值和类型的测试。
3.单元测试
def func1(a,b,c,d,e):
“”“
@a:
”“”
pass
3. 命名
下划线命名线 get_doc
驼峰命名法 getDocFromUrl
为何要用默认值:
1.更省事
2.更可配置
4.练习题
三. 函数第3节
1. assert
在开发一个程序时候,与其让它运行时崩溃,不如在它出现错误条件时就崩溃(返回错误)。这时候断言assert就显得很是有用。
assert不能放在程序流程中,它是用于程序调试的
例1. 下面使用assert的方式是不对的
for item in args:
assert isinstance(item,int),'parameter is integer only'
return max(args),min(args)
例2
这段代码用来检测数据类型的断言,由于 a_str 是 str 类型,因此认为它是 int 类型确定会引起错误。
>>> a_str = 'this is a string'
>>> type(a_str)
<type 'str'>
>>> assert type(a_str)== str
>>> assert type(a_str)== int
Traceback (most recent call last):
File "<pyshell#41>", line 1, in <module>
assert type(a_str)== int
AssertionError
2.自省与函数---func.__code__
例如
def func1(arg1,arg2):
return arg1 == arg2
print dir(func1.__code__)
print func1.__code__.co_varnames #('arg1', 'arg2'),返回函数的参数
print func1.__code__.co_filename #test1.py,返回脚本的文件名。
print help(func1.__code__)
都试一下会输出什么
3.做用域问题再议
例子1
arg = 1
def func1():
arg = 3
func1()
print arg
返回结果是1,说明局部变量只会在函数内部生效。
例子2
arg =1
def func1():
global arg
arg = 3
def func2():
global arg
arg =4
func2()
func1()
print arg
结论:
1) func2()和func1()的顺序不一样,输出结果也会不一样
2) global关键字能够把局部变量变为全局变量
4.可变参数的魔法与禁忌
例子1
def func1(arg):
arg[0] = 5 用于测试
return arg
print func1([1,2,3])
结果为[5,3,4],参数arg为列表,是可变的参数。
例子2
def func1(arg):
arg[0] = 5 用于测试
return arg
tlist = [1,2,3]
print func1(tlist)
print tlist #引入可变参数会很危险,这里引入的tlist参数本身也被修改了
四. 函数第4节
step1:lambda之再议
1.lambda是一个表达式,它没有名称,存储的也不是代码块,而是表达式。
2.它被用做执行很小的功能,不能在里面使用条件语句。可是能够执行三元表达式,好比例2
3.也能够执行列表推导式,好比例子3
例子1
d = lambda x:x+1
print d(2)
输出为3,等价于函数
def e(x)
return x+1
例子2
>>> d = lambda x:x+1 if x>0 else "error"
>>> print d(3)
4
>>> print d(-1)
error
例子3
>>> g = lambda x:[(x,i) for i in xrange(0,10)]
>>> print g(3)
[(3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9)]
例子4
>>> t = [1,2,3,4,5]
>>> g = filter(lambda x:x>3,t) #自动把t的值代入x中
>>> print g
[4, 5]
step2:函数参数总结
1.位置匹配 func(name)
def func(arg1,arg2,arg3):
return arg1,arg2,arg3
print func(1,2,3) #按位置传参
2.关键字匹配 func(key=value)
def test(a='',b='None',c=''):
return a,b,c
print test(a=2,c=3)
print test(c=9,a=1)
print test(a=3,b=4,c=5)
print test()
输出结果以下
(2, 'None', 3)
(1, 'None', 9) #说明参数顺序变化也不要紧
(3, 4, 5)
('', 'None', '')
3.收集匹配
若是是在参数中没有定义的位置参数,就会设为元组或者字典;
*kargs 元组
**kw 字典
例子
def func2(a,*kargs,**kw):#比较有位置参数a和没有的区别
return kargs
print func2(2,3,4,5,[1,2,3],{1:2,3:4})
4.参数顺序
参数位置规则:位置匹配参数 > 关键字匹配参数 > 元组参数 > 字典参数; 好比def func2(a,d,b=4,*kargs,**kw)
step3:接触递归
1.递归是调用自身
2.理解下面的函数
"""
def func(i):
if i<100:
return i + func(i+1)
return i
print func(3)
print func(10)
"""
五. 面向对象
初识class
1. class的基本定义
class test(object):
a=1 #a称为test的属性
def func_1(self): #在类中定义的函数被称为方法,方法的第一个参数必须是self。
pass
t = test()
print t.a
print t.func_1()
2. __init__方法-------构造函数,
做用:实例化以前能够先引入一些必要的参数
例子1:定义一个空方法
def __init__(self):
pass
例子2:
class Person: #类名后面不加参数也行
def __init__(self,name,age):
self.name=''
self.age=0
p=person('tom',20)
print p
这样的输出结果是
hong@hong-VirtualBox:~$ python test2.py
<__main__.person instance at 0x7f5f8104c560>
例子3:将对象的内容打印出来
class test(object): #全部的class都是object的派生类
def __init__(self,var1): #注意这里的逗号
self.var1 = var1 #把参数var1赋值给self.var1,这样self.var1就能在类中进行全局调用
def get(self,a=None): #把参数a去掉和a=None是等效的,这样就不用引入参数了
return self.var1 #全局调用self.var1,通常的函数是不能使用在其余函数中的变量的
t = test("hello,my name is hong")
print t.get()
例子4:用于生成对象的字符串表示的方法__str__
class test:
def __init__(self,var1):
self.var1 = var1
def get(self,a=None):
return self.var1
def __str__(self):
return self.var1
t = test("hello, my name is hong")
print t.get()
print type(t.get())
print str(t)
print type(str(t))
输出以下
hello, my name is hong
<type 'str'>
hello, my name is hong
<type 'str'>
注意:这里get方法和__str__方法是等效的。
例子5:把上例改为2个参数
class test:
def __init__(self,var1,var2):
self.var1 = var1
self.var2 = var2
def get(self):
return self.var1,self.var2
def __str__(self):
return self.var1,self.var2
t = test("hello",33)
print t.get()
print str(t)
这样写会返回一个错误
hong@hong-VirtualBox:~$ python test2.py
('hello', 33)
Traceback (most recent call last):
File "test2.py", line 13, in <module>
print str(t)
TypeError: __str__ returned non-string (type tuple)
改为以下代码就对了,本身琢磨一下
class test:
def __init__(self,var1,var2):
self.var1 = var1
self.var2 = var2
def get(self):
return self.var1,self.var2
def __str__(self):
return "(%s,%d)" % (self.var1,self.var2)
t = test("hello",33)
print t.get()
print type(t.get())
print str(t)
print type(str(t))
输出结果以下
hong@hong-VirtualBox:~$ python test2.py
('hello', 33)
<type 'tuple'>
(hello,33)
<type 'str'>
3. 析构函数,是用做销毁的,这种方法不经常使用,由于class被销毁时,python有内部机制会自动销毁里面的数据。
def __del__(self):
del self.arg1
del self.arg2
t = test(1,4)
print t.a
print t.func_1()
4. class和函数的区别
例子1:一个最基本的对象
class test(object):#若是是空类,能够继承object类
def get(self): #类里面定义函数,其中的参数self表明的是对象自己,能够在class内部全局调用
return "hello"
对比一下,定义一个基本函数
def get():
return "hello"
t = test() #t是test的一个实例
print t.get() #get称为test对象的专属方法,不能被其余函数调用,这个就是使用对象的内置方法
print get() #自定义的函数和对象的内置方法进行对比
例2. 在get()函数中增长一个参数a
class test(object):
def get(self,a): #引入一个参数a,
return a
def got(a): #自定义的函数也引入一个参数a
return a
t = test()
new_var = 4
print t.get(new_var)
print got(new_var)
输出都是4
5. 私有变量
再person中,在变量名age开头加上2个下划线,代表age是私有变量,这样age只能person类中访问;不如下划线打头的变量是公有变量,任何代码均可访问他们。
在编写大型程序时,一条实用的经验规则是,首先将全部对象变量都设置为私有的(即以2个下划线打头),再在有充分理由的状况下将其改成公有的,能够避免无心间修改对象内部变量致使的错误。
6. __repr__和__str__的区别
class Test(object):
def __init__(self, value='hello, world!'):
self.data = value #这里说明并不是必定写成self.value=value
>>> t = Test()
>>> t
<__main__.Test at 0x7fa91c307190>
>>> print t
<__main__.Test object at 0x7fa91c307190>
我测试的是t和print t,效果是同样的。
# 看到了么?上面打印类对象并非很友好,显示的是对象的内存地址# 下面咱们重构下该类的__repr__以及__str__,看看它们俩有啥区别
1) 重构__repr__class TestRepr(Test):
def __repr__(self):
return 'TestRepr(%s)' % self.data
>>> tr = TestRepr()
>>> tr
TestRepr(hello, world!)
>>> print tr
TestRepr(hello, world!)
# 重构__repr__方法后,无论直接输出对象仍是经过print打印的信息都按咱们__repr__方法中定义的格式进行显示了
2) 重构__str__
calss TestStr(Test):
def __str__(self):
return '[Value: %s]' % self.data
>>> ts = TestStr()
>>> ts
<__main__.TestStr at 0x7fa91c314e50>
>>> print ts
[Value: hello, world!]
# 你会发现,直接输出对象ts时并无按咱们__str__方法中定义的格式进行输出,而用print输出的信息却改变了
总结:
__repr__和__str__这两个方法都是用于显示的,__str__是面向用户的,而__repr__面向程序员。
- 打印操做会首先尝试__str__和str内置函数(print运行的内部等价形式),它一般应该返回一个友好的显示。
- __repr__用于全部其余的环境中:用于交互模式下提示回应以及repr函数,若是没有使用__str__,会使用print和str。它一般应该返回一个编码字符串,能够用来从新建立对象,或者给开发者详细的显示。
当咱们想全部环境下都统一显示的话,能够重构__repr__方法;当咱们想在不一样环境下支持不一样的显示,例如终端用户显示使用__str__,而程序员在开发期间则使用底层的__repr__来显示,实际上__str__只是覆盖了__repr__以获得更友好的用户显示
7. 装饰器
1. @property,这个东西能够直接把函数当作属性来用,例如
class test(object):
@property
def d(self):
return 4
t=test()
print t.d #使用了装饰器,这里能够直接写t.d,就能够输出值,而不是t.d()
2. @staticmethod装饰器,能够不把类test实例化,就能使用其中的方法,以下
class test(object):
@staticmethod #静态方法,把命名空间放在了类test中
def d(): #这里不须要加self参数了,类的普通内置方法的时候才会加self参数,这里和在类外面定义的函数是同样的
return 4
print test.d() #不用实例化,直接用class的名称来执行。
8. 继承
例子1
class Base(object):
def __init__(self,name)
self.name = name
class b(Base): #至关于在b中也有一个init函数
def get_name(self):
return self.name #若是写name就是错误的
new_class = b("lilei") #把b实例化
print new_class.get_name()
六. 模块
1.模块的基本概念
模块其实就是一个py文件,好比python内置模块linecache,能够用dir(linecache)查看模块内置方法
2.导入模块的方法
1)import #导入所有方法
import linecache
>>> dir(linecache)
['__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'cache', 'checkcache', 'clearcache', 'getline', 'getlines', 'os', 'sys', 'updatecache']
>>> linecache.__file__ #linecache的脚本文件位置
'/usr/lib/python2.7/linecache.pyc'
2)from module import sth,只导入模块中的某个方法
from linecache import getlines,这样就能够直接使用getlines方法
>>getlines
3)from module import all 导入所有方法
from linecache import *, 这种方式不会导入如下划线 (_) 开头的名称。
注意点,
1)在linecache的脚本文件中,有__all__ =["getline","clearcache","checkcache"],这样用from linecache import *命令导入时,只会导入getline,clearcache,checkcache这三个方法,这三个方法至关于公有方法,全部人均可以使用;其余的方法至关于linecache的私有方法,好比updatecache,其余人不能任意用,使用import linecache时,就不会有这个限制。
2)当用这个方法导入多个模块的时候,不一样模块中的方法名字可能会冲突,因此要慎用!
3.自定义模块
例如自定义个模块 m1
#coding=utf-8
def hash():
return 4
那么在其余脚本中就可使用m1
#coding=utf-8
import m1
print m1.hash()
4.包的建立
包是一群模块的组合,因此先建一个文件夹,好比m2,做为包
1)写初始化文件 __init__.py #此时为空
为了让 Python 将目录当作包,目录下必须包含 __init__.py 文件;这样作是为了防止一个具备常见名字(例如 string)的目录无心中隐藏目录搜索路径中正确的模块。最简单的状况下,__init__.py 能够只是一个空的文件,但它也能够为包执行初始化代码或设置__all__
2)定义一个url.py
#coding=utf-8
def get_page():
return "some page content"
3)在其余脚本中引用包
注意使用from package import item时,item 能够是包的子模块(或子包),也能够是包中定义的一些其它的名称,好比函数、 类或者变量。import语句首先测试 item 在包中是否有定义;若是没有,它假定它是一个模块,并尝试加载它。若是未能找到,则引起ImportError异常。
相反,使用相似 import item.subitem.subsubitem 这样的语法时,除了最后一项其它每项必须是一个包;最后一项能够是一个模块或一个包,但不能是在前一个项目中定义的类、函数或变量
#coding=utf-8
import m2
print dir(m2)#查看都什么内置模块
print m2.__file__ #会导入init文件
#print m2.url是不会调用url.py文件的,执行脚本的时候会出错,那么怎么调用呢?
方法1 -----在python命令行,以及在linux脚本中都能执行
import m2.url
print m2.url
#若是以为m2.url比较麻烦,能够用import m2.url as url更名,as至关于一个赋值操做,代码以下
import m2.url as url
print url.get_page()
执行结果:
输出getpage()定义的文本信息:some page content
方法2 ---这种方法能够在python命令行中执行,可是在linux的脚本中不能执行。
from m2 import url
print url.get_page()
若是只想使用url的get_page方法,怎么办呢?
方法1
from m2.url import get_page
print get_page()
方法2
from m2 import *
print url.get_page()
那么此时就须要在__init__.py中进行定义__all__ = ["url"],可是经验证,不用在__inti__.py中定义也行。
5. 搜索模块
若是在上面的包中再写一个模块,好比test2.py, 这个在包里的模块怎么引入外部的模块呢? 好比外部模块为m1.py
import sys
sys.path.append("/tmp/m") #添加模块搜索路径,m文件夹中包含着m1.py文件,其实就是定位m1的位置。
import m1
print m1.bash() #调用m1的bash()方法,视频中多了代码 __all__ = ['hash'],测试下不会影响吗?经验证,不会影响。
6. 经常使用模块
1.咱们去哪里找模块
2.咱们应该首先选择哪些的模块
3.经常使用模块
3.1 urllib,urllib2 --- 网络方面的模块
import urllib #urllib多是一个包,包和模块的用法是同样的
dir(urllib)
help(urllib)里面FILE有脚本文件的位置信息
使用方法,好比获取网页内容
print d.read()
3.2 datetime, time --- 时间模块
import time
time.time() #获得一个时间戳
import datetime
使用help(datetime),看MODULE DOCS中的网站能够看到很是详细的例子
3.3 os --- 系统模块
import os
3.4 pickle --- 对象序列化
经常使用数据交换格式 还有json, xml
import pickle
例子
class test(object):
def a(self):
return 4
def b(self):
return 5
d = test() #想把对象作持久化保存,好比放在文件里,那么须要把对象转变为字符串,就须要用到pickle
g=pickle.dumps(d) #对象转为字符串
type(g) #这里就转变成字符串了
g=pickle.loads(g) #反序列化,字符串转为对象
3.5 bsddb --- 一个轻量级的数据库,支持key=>value的字典形式
3.6 logging --- 日志
掌握 info, warning, error,重点看一下
七,异常
exception,中译异常,保守派的圣杯,被滥用的良药。
1. 出错的东西们,他们出了什么错,他们出错 = 被抛出了异常
2. 咱们不想让他们出错,继续执行下面的程序,该怎么办?exception来了。
coding=utf-8
a = [1,2,3,4,5,6]
print a[5]
try:
print a[6]
except: #捕获异常
print u"哈哈哈哈,这里出错啦" #出错之后该作什么,这里输出出错信息
print '继续往下跑哦'
3. 基本语法
try:
" 框住了你感受会抛出异常的代码 "
print "41223123"
print a[6] #这里抛出异常后就会跳到except语句,不会执行下面的print语句。
print "hahaha"
except:
" try代码块里的代码若是抛出异常了,该执行什么内容"
print u"哈哈"
else:
"try代码块里的代码若是没有抛出异常,就执行这里"
print "hoho"
finally:
"无论如何,finally里的代码,是总会执行的"
print "xixi"
4. 异常的应用
import urllib
#异常输出以下
try:
d = urllib.urlopen(sth_url)
except:
print "哈哈哈出错了"
else:
content = d.read()
finally:
d.close()
5.咱们为何不让他出错?
其实在开发阶段,咱们是可让任何东西出错的,这样能更快的排错来完善代码
6.何时用,怎么用?
咱们何时用异常? 答:不得不用的时候。
异常怎么用?
1. (咱们知道会有哪些问题,分析问题,获得这些问题会抛出的指定异常)捕获不一样的异常状况,最好不要只写except,这样捕获全部异常比较笼统。
好比上面的例子,能够经过写多个except语句,完善以下
try:
d = urllib.urlopen(sth_url)
except IOError: #打不开网页的异常,这里的IOError是网页不对时python输出的异常信息。
print "网页出错了"
except 语法错误异常:
print "语法错误"
else:
content = d.read()
finally:
d.close()
2.异常的处理,要合理。要有日志。