实习日记(第一周)


markdown学习

斜体
粗体

这是一级标题

这是二级标题

这是一个参考式链接
这是一个行内式链接

这是一个引用示例(在首行插入>表示引用)

//标记代码区域(或者用~~~或者缩进4个空格或者tab)
void main()
{
  cout<<"hello world"<
  • 无序列表
    *或+或-都是无序列表

    1. 有序列表1
    2. 有序列表2

    markdowm有序列表在Atom中默认从1开始

名字 性别 年龄 身高
小明 18 160
小王 21 161
默认方式对齐
:— 左对齐
:—: 居中对齐
—: 右对齐

Atom支持qq截屏图片复制粘贴进来

行内式插入图片

参考式插入图片

脚注:添加脚注只需要在想要加脚注的文字后面插上[^脚注标记]。然后你可以在文件任意位置将脚注内容写出来,脚注内容会显示在文件的最后。
[^脚注01]: 这是一个脚注的注释

转义:在以下字符前面插入反斜杠,插入之后,将不再解析这些字符,而是原样输出。
\ 反斜线
` 反引号
* 星号
_ 底线
{} 花括号
[] 方括号
() 括弧
# 井字号
+ 加号
- 减号
. 英文句点
! 惊叹号


python学习

python基础

  1. 第一个python程序//无须分号结尾,注意缩进
    print”hello world”
  2. python文件必须是.py结尾;文件名必须是英文字母,数字和下划线组成
  3. 在windows命令行模式下输入python hello.py运行python文件;
    在linux和mac系统上可以在.py文件第一行加上#!/usr/bin/env python,
    然后通过命令#!/usr/bin/env python运行.py文件
  4. 输入输出:
name=raw_input("please enter your name")
>>>print "hello"+name
  1. 数据类型和变量(整数运算是精确的,而浮点数运算有误差;变量名必须是英文字母,数字和_的组合且变量名不能以数字开头)
  2. 字符串和格式化(字母和数字相互转换ord(‘A’)、chr(‘65’);格式化用%实现)
  3. list(集合)有序可变和tuple(元组)有序不变
  4. 结束死循环用ctrl+C
  5. dict(字典)键值存储,具有极快的查找速度。避免key不存在的错误1、a in b 2、b.get(‘a’,-1)。删除key用pop(key)方法
  6. 和list比较,dict有以下几个特点:
    1查找和插入的速度极快,不会随着key的增加而增加;
    2需要占用大量的内存,内存浪费多。
    而list相反;所以,dict是用空间来换取时间的一种方法
  7. set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。
    要创建一个set,需要提供一个list作为输入集合;重复元素在set中自动被过滤;set可以看成数学意义上的无序和无重复元素的集合,
    因此,两个set可以做数学意义上的交集、并集等操作

函数

  1. 函数:空函数用pass;默认参数可以简化函数的调用。设置默认参数时,有几点要注意:
    一是必选参数在前,默认参数在后,否则Python的解释器会报错;二是如何设置默认参数。
  2. 定义可变参数和定义list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数
def calc(*numbers):
    sum = 0
    for n in numbers:
      sum = sum + n*n
    return sum
  1. 可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。
    而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
def person(,age,**kw):
  print 'name:',name,'age:',age,'other','kw'

在Python中定义函数,可以用必选参数、默认参数、可变参数和关键字参数,这4种参数都可以一起使用,或者只用其中某些,
但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数和关键字参数.

高级特性

  1. 切片(方便取元素,倒数第一个元素为-1)
  2. 迭代(可以用for循环遍历)
  3. 列表生成式:
L=[]
for x in range(1,11):
  L.append(x*x)
[x*x for x in range(1,11)]
[x*x for x in range(1,11) if x%2 == 0 ]
[m+n for m in 'ABC'for n in 'XYZ']
>>>L=['Hello','World','IBM','Apple']
>>>[s.lower() for s in L]
['hello','world','ibm','apple']
>>>x = 'abc'
>>>y = 123
>>>isinstance(x,str)
True
>>>isinstance(y,str)
False
  1. 生成器:generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

函数式编程

  1. 函数式编程:是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。
    函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!
    Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。
  2. 高阶函数:变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
def add(x,y,f):
    return f(x)+f(y)
  1. map:函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回
>>> def f(x):
...     return x * x
...
>>> map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
[1, 4, 9, 16, 25, 36, 49, 64, 81]
  1. reduce:reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。
>>> def add(x, y):
...     return x + y
...
>>> reduce(add, [1, 3, 5, 7, 9])
25

利用map/reduce将字符串转换为整形

def str2int(s):
    def fn(x, y):
        return x * 10 + y
    def char2num(s):
        return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
    return reduce(fn, map(char2num, s))

练习1:首字母大写,其他小写

def wgw(x):
    return [x[0].upper()+x[1:].lower()]

练习2:编写一个prod()函数,可以接受一个list并利用reduce()求积

def prod(s):
    def fn(x,y):
        return x*y
    return reduce(fn,s)
  1. filter:过滤序列。和map()类似,filter()也接收一个函数和一个序列。和map()不同的时,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
    练习:删除1~100素数
def sushu(x):
    for n in range(2,x-1):
        if(x%n == 0):
            return x    
  1. sorted:排序算法。通常规定,对于两个元素x和y,如果认为x < y,则返回-1,如果认为x == y,则返回0,如果认为x > y,则返回1,这样,排序算法就不用关心具体的比较过程,而是根据比较结果直接排序。
x=sorted([3,5,9,7,1],reverse=False)
y=sorted([3,5,9,7,1],reverse=True)
print x
print y
  1. 返回函数:高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs
f1, f2, f3 = count()

返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9。
返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:
26. 匿名函数:关键字lambda表示匿名函数,冒号前面的x表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数

>>> map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])
[1, 4, 9, 16, 25, 36, 49, 64, 81]
  1. 装饰器:在面向对象(OOP)的设计模式中,decorator被称为装饰模式。OOP的装饰模式需要通过继承和组合来实现,而Python除了能支持OOP的decorator外,直接从语法层次支持decorator。Python的decorator可以用函数实现,也可以用类实现。(难点)
    decorator可以增强函数的功能,定义起来虽然有点复杂,但使用起来非常灵活和方便。
    练习1:
    练习2:
  2. 偏函数:当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85

模块

  1. _future_模块:把下一个新版本的特性导入到当前版本,于是我们就可以在当前版本中测试一些新版本的特性。由于Python是由社区推动的开源并且免费的开发语言,不受商业公司控制,因此,Python的改进往往比较激进,不兼容的情况时有发生。Python为了确保你能顺利过渡到新版本,特别提供了__future__模块,让你在旧的版本中试验新版本的一些特性。

面向对象编程

  1. 类:类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的。通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。定义类是通过class关键字。和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别
class Student(object):
    pass
  1. 实例:实例是根据类创建出来的一个个具体的“对象”,创建实例是通过类名+()实现的。
>>> bart = Student()
>>> bart
<__main__.Student object at 0x10a67a590>
>>> Student
<class '__main__.Student'>
  1. 访问限制:要让内部属性不被外部访问,可以把属性的名称前加上两个下划线,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问.
class Student(object):

    def __init__(self, name, score):
        self.__name = name
        self.__score = score

    def print_score(self):
        print '%s: %s' % (self.__name, self.__score)

双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量
33. 继承和多态:当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写;
有了继承,才能有多态。在调用类实例方法的时候,尽量把变量视作父类类型,这样,所有子类类型都可以正常被接收;
旧的方式定义Python类允许不从object类继承,但这种编程方式已经严重不推荐使用。任何时候,如果没有合适的类可以继承,就继承自object类。
34. type():判断对象是什么类型;isinstance(a,int):判断是否是某个类型。

面向对象高级编程

  1. __slots__:限制class能添加的属性.定义的属性仅对当前类起作用,对继承的子类是不起作用的;除非在子类中也定义slots,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__
  2. @property装饰器:就是负责把一个方法变成属性调用
class Student(object):
    @property
    def birth(self):
        return self._birth
    @birth.setter
    def birth(self, value):
        self._birth = value
    @property
    def age(self):
        return 2014 - self._birth

@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
37. Mixin:目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个Mixin的功能,而不是设计多层次的复杂的继承关系.由于Python允许使用多重继承,因此,Mixin就是一种常见的设计。
只允许单一继承的语言(如Java)不能使用Mixin的设计
38. __str__:返回一个好看的字符串,用户看到的;__repr__:返回程序开发者看到的字符串

>>> class Student(object):
...     def __init__(self, name):
...         self.name = name
...     def __str__(self):
...         return 'Student object (name: %s)' % self.name
...
>>> print Student('Michael')
Student object (name: Michael
  1. iter:如果一个类想被用于for … in循环,类似list或tuple那样,就必须实现一个iter()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环
class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1 # 初始化两个计数器a,b

    def __iter__(self):
        return self # 实例本身就是迭代对象,故返回自己

    def next(self):
        self.a, self.b = self.b, self.a + self.b # 计算下一个值
        if self.a > 100000: # 退出循环的条件
            raise StopIteration();
        return self.a # 返回下一个值
>>> for n in Fib():
...     print n
...
1
1
2
3
5
...
46368
75025
  1. __getitem__:实例像list那样按照下标取出元素
class Fib(object):
    def __getitem__(self, n):
        if isinstance(n, int):
            a, b = 1, 1
            for x in range(n):
                a, b = b, a + b
            return a
        if isinstance(n, slice):
            start = n.start
            stop = n.stop
            a, b = 1, 1
            L = []
            for x in range(stop):
                if x >= start:
                    L.append(a)
                a, b = b, a + b
            return L
  1. __getattr__:可以针对完全动态的情况做调用。在没有找到属性的情况下,才调用__getattr__,已有的属性,比如name,不会在__getattr__中查找。此外,注意到任意调用如s.abc都会返回None,这是因为我们定义的__getattr__默认返回就是None。要让class只响应特定的几个属性,我们就要按照约定,抛出AttributeError的错误.
class Student(object):

    def __getattr__(self, attr):
        if attr=='age':
            return lambda: 25
        raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr)
  1. __call__:可以直接对实例进行调用
class Student(object):
    def __init__(self, name):
        self.name = name

    def __call__(self):
        print('My name is %s.' % self.name)
  1. metaclass:元类,允许创建类或者修改类(难点)
#metaclass是创建类,所以必须从`type`类型派生:
class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)
class MyList(list):
    __metaclass__ = ListMetaclass # 指示使用ListMetaclass来定制类

错误,调试和测试

  1. try…except…finally
try:
    print 'try...'
    r = 10 / 0
    print 'result:', r
except ZeroDivisionError, e:
    print 'except:', e
finally:
    print 'finally...'
print 'END'

Python的错误其实也是class,所有的错误类型都继承自BaseException,所以在使用except时需要注意的是,它不但捕获该类型的错误,还把其子类也“一网打尽”

try:
    foo()
except StandardError, e:
    print 'StandardError'
except ValueError, e:
    print 'ValueError'

第二个except永远也捕获不到ValueError,因为ValueError是StandardError的子类,如果有,也被第一个except给捕获了。Python所有的错误都是从BaseException类派生的
45. 调用堆栈:如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。如果不捕获错误,自然可以让Python解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。Python内置的logging模块可以非常容易地记录错误信息:
同样是出错,但程序打印完错误信息后会继续执行,并正常退出

# err.py:
def foo(s):
    return 10 / int(s)
def bar(s):
    return foo(s) * 2
def main():
    bar('0')
main()

在bar()函数中,我们明明已经捕获了错误,但是,打印一个Error!后,又把错误通过raise语句抛出去了,这不有病么?
其实这种错误处理方式不但没病,而且相当常见。捕获错误目的只是记录一下,便于后续追踪。但是,由于当前函数不知道应该怎么处理该错误,所以,最恰当的方式是继续往上抛,让顶层调用者去处理。
raise语句如果不带参数,就会把当前错误原样抛出。此外,在except中raise一个Error,还可以把一种类型的错误转化成另一种类型
46. 调试:1.print打印出来,简单粗暴。2.断言assert,启动Python解释器时可以用-O参数来关闭assert。3.logging,和assert比,logging不会抛出错误,而且可以输出到文件。4.pdb,启动Python的调试器pdb,让程序以单步方式运行,可以随时查看运行状态。

# err.py
def foo(s):
    n = int(s)
    return 10 / n
def bar(s):
    try:
        return foo(s) * 2
    except StandardError, e:
        print 'Error!'
        raise
def main():
    bar('0')
main()
# err.py
def foo(s):
    n = int(s)
    assert n != 0, 'n is zero!'
    return 10 / n
def main():
    foo('0')
# err.py
import logging
s = '0'
n = int(s)
logging.info('n = %d' % n)
print 10 / n

IO编程

  1. 文件读写
>>> f = open('/Users/michael/test.txt', 'r')
with open('/path/to/file', 'r') as f:
    print f.read()
for line in f.readlines():
    print(line.strip()) # 把末尾的'\n'删掉
import codecs
with codecs.open('/Users/michael/gbk.txt', 'r', 'gbk') as f:
    f.read() # u'\u6d4b\u8bd5'
with open('/Users/michael/test.txt', 'w') as f:
    f.write('Hello, world!')
  1. 操作文件和目录:os模块以及os.path模块。
    创建和删除目录
# 查看当前目录的绝对路径:
>>> os.path.abspath('.')
'/Users/michael'
# 在某个目录下创建一个新目录,
# 首先把新目录的完整路径表示出来:
>>> os.path.join('/Users/michael', 'testdir')
'/Users/michael/testdir'
# 然后创建一个目录:
>>> os.mkdir('/Users/michael/testdir')
# 删掉一个目录:
>>> os.rmdir('/Users/michael/testdir')
  1. 序列化:把变量从内存中变成可存储或传输的过程称之为序列化(pickling)。序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
Python提供两个模块来实现序列化:cPickle和pickle。这两个模块功能是一样的,区别在于cPickle是C语言写的,速度快,pickle是纯Python写的,速度慢,跟cStringIO和StringIO一个道理。用的时候,先尝试导入cPickle,如果失败,再导入pickle
try:
    import cPickle as pickle
except ImportError:
    import Pickle
d = dict(name = 'Bob',age = 20,score = 88)
g=pickle.dumps(d)
f = open('dump.txt','wb')
pickle.dump(d,f)
f.close()
print g
f = open('dump.txt','rb')
n = pickle.load(f)
f.close()
print n

输出结果

json:要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。

>>> import json
>>> d = dict(name='Bob', age=20, score=88)
>>> json.dumps(d)
'{"age": 20, "score": 88, "name": "Bob"}'

Python语言特定的序列化模块是pickle,但如果要把序列化搞得更通用、更符合Web标准,就可以使用json模块。
json模块的dumps()和loads()函数是定义得非常好的接口的典范。当我们使用时,只需要传入一个必须的参数。但是,当默认的序列化或反序列机制不满足我们的要求时,我们又可以传入更多的参数来定制序列化或反序列化的规则,既做到了接口简单易用,又做到了充分的扩展性和灵活性。

进程和线程

  1. 多进程:multiprocessing模块提供了一个Process类来代表一个进程对象,创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动。
from multiprocessing import Process
import os
#子进程要执行的代码
def run_proc(name):
    print 'Run child process %s (%s)...' % (name, os.getpid())
if __name__=='__main__':
    print 'Parent process %s.' % os.getpid()
    p = Process(target=run_proc, args=('test',))
    print 'Process will start.'
    p.start()
    p.join()
    print 'Process end.'

如果要启动大量的子进程,可以用进程池的方式批量创建子进程

from multiprocessing import Pool
import os, time, random
def long_time_task(name):
    print 'Run task %s (%s)...' % (name, os.getpid())
    start = time.time()
    time.sleep(random.random() * 3)
    end = time.time()
    print 'Task %s runs %0.2f seconds.' % (name, (end - start))
if __name__=='__main__':
    print 'Parent process %s.' % os.getpid()
    p = Pool()
    for i in range(5):
        p.apply_async(long_time_task, args=(i,))
    print 'Waiting for all subprocesses done...'
    p.close()
    p.join()
    print 'All subprocesses done.'

进程间的通信是通过queue和Pipes实现的

from multiprocessing import Process, Queue
import os, time, random
#写数据进程执行的代码:
def write(q):
    for value in ['A', 'B', 'C']:
        print 'Put %s to queue...' % value
        q.put(value)
        time.sleep(random.random())
#读数据进程执行的代码:
def read(q):
    while True:
        value = q.get(True)
        print 'Get %s from queue.' % value
if __name__=='__main__':
    #父进程创建Queue,并传给各个子进程:
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    #启动子进程pw,写入:
    pw.start()
    #启动子进程pr,读取:
    pr.start()
    #等待pw结束:
    pw.join()
    #pr进程里是死循环,无法等待其结束,只能强行终止:
    pr.terminate()
  1. 多线程:Python的标准库提供了两个模块:thread和threading,thread是低级模块,threading是高级模块,对thread进行了封装。绝大多数情况下,我们只需要使用threading这个高级模块。
    多线程编程,模型复杂,容易发生冲突,必须用锁加以隔离,同时,又要小心死锁的发生。
    Python解释器由于设计时有GIL全局锁,导致了多线程无法利用多核。多线程的并发在Python中就是一个美丽的梦。
  2. Threadlocal:最常用的地方就是为每个线程绑定一个数据库连接,HTTP请求,用户身份信息等,这样一个线程的所有调用到的处理函数都可以非常方便地访问这些资源
import threading
#创建全局ThreadLocal对象:
local_school = threading.local()
def process_student():
    print 'Hello, %s (in %s)' % (local_school.student, threading.current_thread().name)
def process_thread(name):
    # 绑定ThreadLocal的student:
    local_school.student = name
    process_student()
t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()

在Thread和Process中,应当优选Process,因为Process更稳定,而且,Process可以分布到多台机器上,而Thread最多只能分布到同一台机器的多个CPU上。

正则表达式

  1. 正则表达式:正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的。
>>>import re
#编译:
>>>re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$')
#使用:
>>>re_telephone.match('010-12345').groups()
('010', '12345')
>>>re_telephone.match('010-8086').groups()
('010', '8086')

在python使用正则表达式时,re模块内部会1.编译正则表达式,如果正则表达式的字符串本身不合法,会报错;2.用编译后的正则表达式去匹配字符串。如果一个正则表达式要重复使用几千次,出于效率的考虑,我们可以预编译该正则表达式,接下来重复使用时就不需要编译这个步骤了,直接匹配。
练习题:写一个验证Email地址的正则表达式

#-*- coding: utf-8 -*-
import re
regex = r'^(<\w[\s\w]+>\s)?(\w+[\w+.]*@\w+.(org|com)$)'
#题目一:正则匹配
m = re.compile(regex)
#纯Email地址
if m.match('[email protected]'):
    print('match [email protected]')
if m.match('[email protected]'):
    print('match [email protected]')
#带名字的Email地址
if m.match(' [email protected]'):
    print('match  [email protected]')
#题目二:提取带名字的Email地址
m_email = m.match(' [email protected]').group(2)
print(m_email)

常用内建模块

  1. namedtuple:是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素。
    可以很方便地定义一种数据类型,它具备tuple的不变性,又可以根据属性来引用,使用十分方便.
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(1, 2)
>>> p.xfrom coll
1
>>> p.y
2
  1. deque:使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。
    deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈.
>>> from collections import deque
>>> q = deque(['a', 'b', 'c'])
>>> q.append('x')
>>> q.appendleft('y')
>>> q
deque(['y', 'a', 'b', 'c', 'x'])
  1. defaultdict:使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict;
    除了在Key不存在时返回默认值,defaultdict的其他行为跟dict是完全一样的.
>>> from collections import defaultdict
>>> dd = defaultdict(lambda: 'N/A')
>>> dd['key1'] = 'abc'
>>> dd['key1'] # key1存在
'abc'
>>> dd['key2'] # key2不存在,返回默认值
'N/A'
  1. OrderedDict:使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。
    如果要保持Key的顺序,可以用OrderedDict.
>>> from collections import OrderedDict
>>> d = dict([('a', 1), ('b', 2), ('c', 3)])
>>> d # dict的Key是无序的
{'a': 1, 'c': 3, 'b': 2}
>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])

要内容和顺序完全相同才会视为相等;注意顺序以添加顺序为准,和修改的顺序无关。
1. Counter:是dict的一个子类,一个简单的计数器。

>>> from collections import Counter
>>> c = Counter()
>>> for ch in 'programming':
...     c[ch] = c[ch] + 1
...
>>> c
Counter({'g': 2, 'm': 2, 'r': 2, 'a': 1, 'i': 1, 'o': 1, 'n': 1, 'p': 1})
  1. base64:是一种最常见的二进制编码方法
>>> import base64
>>> base64.b64encode('binary\x00string')
'YmluYXJ5AHN0cmluZw=='
>>> base64.b64decode('YmluYXJ5AHN0cmluZw==')
'binary\x00string'
  1. struct:struct的pack函数把任意数据类型变成字符串
>>> import struct
>>> struct.pack('>I', 10240099)
'\x00\x9c@c'
  1. hashlib:提供了常见的摘要算法,如MD5,SHA1等等;摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)
    摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。
import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?')
print md5.hexdigest()
  1. itertools:提供了用于操作迭代对象的函数。
    cycle()会把传入的一个序列无限重复下去;
>>> import itertools
>>> cs = itertools.cycle('ABC') # 注意字符串也是序列的一种
>>> for c in cs:
...     print c
...
'A'
'B'
'C'
'A'
'B'
'C'
...

repeat()负责把一个元素无限重复下去,不过如果提供第二个参数就可以限定重复次数

>>> ns = itertools.repeat('A', 10)
>>> for n in ns:
...     print n
...
打印10'A'

takewhile()函数根据条件判断来截取出一个有限的序列

>>> natuals = itertools.count(1)
>>> ns = itertools.takewhile(lambda x: x <= 10, natuals)
>>> for n in ns:
...     print n
...
打印出110

chain()可以把一组迭代对象串联起来,形成一个更大的迭代器

for c in itertools.chain('ABC', 'XYZ'):
    print c
# 迭代效果:'A' 'B' 'C' 'X' 'Y' 'Z'

groupby()把迭代器中相邻的重复元素挑出来放在一起

>>> for key, group in itertools.groupby('AAABBBCCAAA'):
...     print key, list(group) # 为什么这里要用list()函数呢?
...
A ['A', 'A', 'A']
B ['B', 'B', 'B']
C ['C', 'C']
A ['A', 'A', 'A']

imap()和map()的区别在于,imap()可以作用于无穷序列,并且,如果两个序列的长度不一致,以短的那个为准。

>>> for x in itertools.imap(lambda x, y: x * y, [10, 20, 30], itertools.count(1)):
...     print x
...
10
40
90

imap()返回一个迭代对象,而map()返回list。当你调用map()时,已经计算完毕

>>> r = map(lambda x: x*x, [1, 2, 3])
>>> r # r已经计算出来了
[1, 4, 9]

itertools模块提供的全部是处理迭代功能的函数,它们的返回值不是list,而是迭代对象,只有用for循环迭代的时候才真正计算
1. XML:操作XML有两种方法:DOM和SAX。DOM会把整个XML读入内存,解析为树,因此占用内存大,解析慢,优点是可以任意遍历树的节点。SAX是流模式,边读边解析,占用内存小,解析快,缺点是我们需要自己处理事件。
正常情况下,优先考虑SAX,因为DOM实在太占内存。

web开发

  1. WSGI:WSGI接口定义非常简单,它只要求Web开发者实现一个函数,就可以响应HTTP请求
#hello.py
def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return '

Hello, %s!

'
% (environ['PATH_INFO'][1:] or 'web')
#server.py
#从wsgiref模块导入:
from wsgiref.simple_server import make_server
#导入我们自己编写的application函数:
from hello import application
#创建一个服务器,IP地址为空,端口是8000,处理函数是application:
httpd = make_server('', 8000, application)
print "Serving HTTP on port 8000..."
#开始监听HTTP请求:
httpd.serve_forever()
  1. Flask:使用 Python 编写的轻量级 Web 应用框架
from flask import Flask
from flask import request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def home():
    return '

Home

'
@app.route('/signin', methods=['GET']) def signin_form(): return '''

'''
@app.route('/signin', methods=['POST']) def signin(): # 需要从request对象读取表单内容: if request.form['username']=='admin' and request.form['password']=='password': return '

Hello, admin!

'
return '

Bad username or password.

'
if __name__ == '__main__': app.run()
  1. MVC:Model-View-Controller,中文名“模型-视图-控制器”
from flask import Flask, request, render_template
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def home():
    return render_template('home.html')
@app.route('/signin', methods=['GET'])
def signin_form():
    return render_template('form.html')
@app.route('/signin', methods=['POST'])
def signin():
    username = request.form['username']
    password = request.form['password']
    if username=='admin' and password=='password':
        return render_template('signin-ok.html', username=username)
    return render_template('form.html', message='Bad username or password', username=username)
if __name__ == '__main__':
    app.run()

得将运行的xxx.py文件放到路径C:\Users\Administrator\myvir\Scripts中,在cmd中输入指令python xxx.py启动,然后在浏览器中输入地址http://localhost:5000/才可以访问。

协程

  1. 第三方的gevent为Python提供了比较完善的协程支持,当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。
    使用gevent,可以获得极高的并发性能,但gevent只能在Unix/Linux下运行,在Windows下不保证正常安装和运行。
from gevent import monkey; monkey.patch_socket()
import gevent
def f(n):
    for i in range(n):
        print gevent.getcurrent(), i
g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()

主要参考学习:
廖雪峰的官方网站:
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000

你可能感兴趣的:(实习周记)