进阶篇知识点

 
 
 
前言
 
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基础教程
6)官方文档 docs.python.org
 
 
 
一,函数
 
 
进阶篇 函数 第一节
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.我们去哪里找模块
pypi.python.org  ---- 这个网站有大量的python的模块库
docs.python.org/2.7/  ---- python文档,其中Library Reference包含所有的内置模块的说明
 
2.我们应该首先选择哪些的模块
首先考虑的是内置模块, 相关文档:http://docs.python.org/2.7/
 
3.常用模块
 
3.1 urllib,urllib2 --- 网络方面的模块
import urllib #urllib可能是一个包,包和模块的用法是一样的
dir(urllib)
help(urllib)里面FILE有脚本文件的位置信息
使用方法,比如获取网页内容
d = urllib.urlopen("http://www.baidu.com";)
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
#异常输出如下
sth_url = "http://wasdasdasd";
try:
    d = urllib.urlopen(sth_url)
except:
    print "哈哈哈出错了"
else:
    content = d.read()
finally:
    d.close()
 
5.我们为什么不让他出错?
其实在开发阶段,我们是可以让任何东西出错的,这样能更快的排错来完善代码
 
6.什么时候用,怎么用?
  我们什么时候用异常? 答:不得不用的时候。
  异常怎么用?
1. (我们知道会有哪些问题,分析问题,得到这些问题会抛出的指定异常)捕获不同的异常情况,最好不要只写except,这样捕获所有异常比较笼统。
比如上面的例子,可以通过写多个except语句,完善如下
 
sth_url = "http://wasdasdasd";
try:
    d = urllib.urlopen(sth_url)
except IOError: #打不开网页的异常,这里的IOError是网页不对时python输出的异常信息。
    print "网页出错了"
except 语法错误异常:
    print "语法错误"
else:
    content = d.read()
finally:
    d.close()
 
2.异常的处理,要合理。要有日志。
 
 
 
posted @ 2018-03-06 15:40  坚强的小蚂蚁  阅读(228)  评论(0编辑  收藏  举报