• 进阶篇知识点


     
     
     
    前言
     
    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.异常的处理,要合理。要有日志。
     
     
     
  • 相关阅读:
    JavaScript getElementByID() not working
    [转] 从此不再惧怕URI编码:JavaScript及C# URI编码详解
    win 8.1 突然没有了声音 -- 解决办法
    升级打怪第一天 -------字符串重复
    Flex布局
    HTML 的全局事件属性
    CSS position 相对定位和绝对定位
    将1100秒转换为分秒格式
    新手小白的上路之旅
    谈谈我对Manacher算法的理解
  • 原文地址:https://www.cnblogs.com/regit/p/8514699.html
Copyright © 2020-2023  润新知