函数

1.注意:函数的默认参数必须指向不可变对象

未修改前:

  1. def add_end(L=[]):
  2. L.append('END')
  3. return L

存在的问题:如果连续调用多次,会出现多个 'END' 对象

原因解释:

Python函数在定义的时候,默认参数L就被计算出来了,即 [] ,因为默认参数L指向了可变对象[],每次调用的时候,如果改变了L的内容,下次调用的时候,L指向的内容也发生了改变,不再是函数定义时候的 [] 了。

修改后:

  1. def add_end(L=None):
  2. if L is None:
  3. L = []
  4. L.append('END')
  5. return L

这样无论调用多少次都不会出问题。

2.关键字参数

  func(xx,xxx,**kw)

  1. def person(name,age,**kw):
  2. print('name:',name,'age:',age,'other:',kw)
  3.  
  4. extra = {'city': 'BeiJing','job': 'Python'}
  5. person('XM',23,**extra)
  6.  
  7. # 输出
  8. # name: XM age: 23 other: {'city': 'BeiJing', 'job': 'Python'}

  注意:**extra表示把extra这个dict的所有key-value用关键字参数传递给函数的**kw参数,kw将获得一个dict,注意获得dict是extra的一份拷贝,修改kw不会对extra有任何影响。

高级特性模块

1.迭代器

可以被next()函数调用并不断返回下一个值的对象成为迭代器Iterator,可以使用isinstance()判断一个对象是否是Iterator对象

  1. >>> from collections import Iterator
  2. >>> isinstance((x * x for x in range(10)),Iterator)
  3. True
  4. >>> isinstance([],Iterator)
  5. False
  6. >>> isinstance({},Iterator)
  7. False

生成器都是Iterator对象,但是list、dict、str、虽然是Iterable,却不是Iterator。

把list、dict、str等Iterable变成Iterator,可以使用iter()函数

  1. >>> isinstance(iter([]),Iterator)
  2. True
  3. >>> isinstance(iter({}),Iterator)
  4. True

函数式编程

fitler用法

把一个序列中的空字符串删掉

  1. # 1.把一个序列中的空字符串删掉
  2. def not_empty(s):
  3. return s and s.strip()
  4.  
  5. li = ['A','',None,'B',' ','C']
  6. li = list(filter(not_empty,li))
  7. print(li)

闭包

返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量

  1. # 返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量
  2. def count():
  3. fs = []
  4. for i in range(1,4):
  5. def f():
  6. return i * i
  7. fs.append(f)
  8. return fs
  9.  
  10. f1,f2,f3 = count()
  11. print(f1()) # 输出9
  12. print(f2()) # 输出9
  13. print(f3()) # 输出9
  14.  
  15. # 原因就在于返回的函数引用了变量i,但它并非立刻执行,等到3个函数都返回时,他们所引用的变量i,已经变成了3
    # 因此最终结果都为9
  16.  
  17. # 如果一定要引用循环变量怎么办?方法就是在创建一个函数,用该函数的参数绑定循环变量当前的值,无论循环变量后期如何变化
  18. # 已绑定到函数参数的值不变
  19.  
  20. def count():
  21. def f(j):
  22. def g():
  23. return j * j
  24. return g
  25. fs = []
  26. for i in range(1,4):
  27. fs.append(f(i))
  28. return fs
  29.  
  30. f1,f2,f3 = count()
  31. print(f1()) # 输出1
  32. print(f2()) # 输出4
  33. print(f3()) # 输出9

装饰器

  1. # 定义装饰器
  2. def log(func):
  3. def wrapper(*args,**kwargs):
  4. print('call %s()' % func.__name__)
  5. func(*args,**kwargs)
  6. return wrapper
  7.  
  8. @log
  9. def now():
  10. print('2018-04-25')
  11.  
  12. # 调用now函数
  13. now()
  14.  
  15. # 输出
  16. # call now()
  17. # 2018-04-25

解释:把@log放到now()函数定义处,相当于执行了语句
now = log(now)
由于log()是一个decorator,返回一个函数,所以原来的now()函数仍然存在,只是现在同名的now()指向了新的函数,于是调用now()将执行新的函数,即在log()函数中返回的wrapper()函数

如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数

  1. def log(txt):
  2. def decorator(func):
  3. def warpper(*args,**kwargs):
  4. print('%s %s' % (txt,func.__name__))
  5. return func(*args,**kwargs)
  6. return warpper
  7. return decorator
  8.  
  9. @log('execute')
  10. def now():
  11. print('2018-04-25')
  12.  
  13. # 调用now()函数
  14. now()
  15. print('%s' % now.__name__)
  16.  
  17. # 输出
  18. # execute now
  19. # 2018-04-25
  20. # wrapper

解释:和两层嵌套decorator相比,3层嵌套的效果是这样的:
now = log('execute')(now)
我们来剖析上面的语句,首先执行log('execute')返回的是decorator()函数,在调用返回的函数参数是now()函数,返回值最终是wrapper()函数

最后一步:因为我们讲的是函数也是对象,他有__name__等属性,但是你去看经过decorator()函数装饰之后的函数,他们的__name__已经从原来的的'now'变成'wrapper'了
所以需要将原始函数的__name__等属性复制到wrapper()函数中,否则又一些以来函数签名的代码执行要出错。
不需要编写wrapper.__name__ = func.__name__这样的代码,Python中内置了functools.wraps就是干这事的,所以一个完整的decorator的写法如下:

  1. from functools import wraps
  2.  
  3. def log(func):
  4. @wraps(func)
  5. def wrapper(*args,**kwargs):
  6. print('call %s' % func.__name__)
  7. return func(*args,**kwargs)
  8. return wrapper
  9.  
  10. @log
  11. def now():
  12. print('2018-04-25')
  13.  
  14. # 调用函数
  15. now()
  16. print(now.__name__)
  17.  
  18. # 输出
  19. # call now
  20. # 2018-04-25
  21. # now
  22.  
  23. def log(txt):
  24. def decorator(func):
  25. @wraps(func)
  26. def wrapper(*args,**kwargs):
  27. print('%s %s' % (txt,func.__name__))
  28. return func(*args,**kwargs)
  29. return wrapper
  30. return decorator
  31.  
  32. @log('execute')
  33. def now():
  34. print('2018-04-25')
  35.  
  36. # 调用函数
  37. now()
  38. print(now.__name__)
  39.  
  40. # 输出
  41. # execute now
  42. # 2018-04-25
  43. # now

偏函数  

通过functools.partial可以帮助我们创建一个偏函数

  1. from functools import partial
  2.  
  3. int2 = partial(int,base=2)
  4. ret = int2('')
  5. print(ret)
  6. # 输出
  7. #
  8.  
  9. max2 = partial(max,10)
  10. ret = max2(2,3,4)
  11. print(ret)
  12. # 输出
  13. #

简单总结functools.partial的作用,就是把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新的函数会更简单

面向对象编程

需要注意的是,在Python中,变量名类似__xxx__的,也就是双下划线开头,双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以不能用__name__、__score__这样的变量名

双下划线开头的实例变量是不是就不能被外部访问了?其实不是的,不能只能访问__name是因为Python解释器对外吧__name变量改成了_Student__name,所以可以通过_Student__name来访问__name变量:

  bart._Student__name

但是强烈不推荐这么做,因为不同版本的Python解释器可能会把__name改成不同的变量名

如何判断一个对象是否是函数怎么办?可以使用types模块中定义的常量:

  1. import types
  2.  
  3. def Animals():
  4. pass
  5. a = Animals()
  6. print(type(Animals) == types.FunctionType)

如何给实例绑定一个方法?

  1. class Student():
  2. pass
  3.  
  4. def set_age(self,age): # 定义一个函数作为实例方法
  5. self.age = age
  6.  
  7. s = Student()
  8.  
  9. from types import MethodType
  10.  
  11. s.set_age = MethodType(set_age,s) # 给实例绑定一个方法
  12. s.set_age(25) # 调用实例方法
  13. print(s.age) # 测试结果

为了给所有实例都绑定方法,可以给class绑定方法:

  1. Student.set_age = MethodType(set_age,Student)
  2.  
  3. s1 = Student()
  4. s1.set_age(12)
  5. print(s1.age)
  6.  
  7. s2 = Student()
  8. s2.set_age(23)
  9. print(s2.age)

__slots__的使用

如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加name和age属性。

为了达到目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:

  1. class Student:
  2. __slots__ = ('name','age') # 用tuple定义绑定的属性名称
  3.  
  4. s = Student()
  5. s.name = 'XM'
  6. s.age = 34
  7. s.score = 98 # 绑定属性score 报错
  8.  
  9. # AttributeError: 'Student' object has no attribute 'score'

除非在子类中也定义__slots__,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__

  1. class GraduateStudent(Student):
  2. __slots__ = ('score') # 除非子类也定义__slots__,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__
  3. pass
  4.  
  5. g = GraduateStudent()
  6. g.score = 97
  7. g.name = 'DN'

@property的使用

  1. class Student:
  2. @property
  3. def score(self):
  4. return self._score
  5.  
  6. @score.setter
  7. def score(self,value):
  8. if not isinstance(value,int):
  9. raise ValueError('score must be int')
  10. if value < 0 or value >100:
  11. raise ValueError('score must be 0~100')
  12. self._score = value
  13.  
  14. s = Student()
  15. s.score = 90
  16. print(s.score)

注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴漏的,而是通过getter和setter方法实现的。还可以设置只读属性,不定义setter方法就是只读属性

__str__和__repr__的区别?

在不使用print的时候,直接显示变量的调用的不是__str__(),而是__repr__(),两者的区别是__str__()返回用看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为了调试服务的。

偷懒的写法是

  1. class Student:
  2. def __init__(self,name):
  3. self.name = name
  4.  
  5. def __str__(self):
  6. print('Student object(name = %s)' % self.name)
  7.  
  8. __repr__ = __str__

__iter__

如果一个类想被用于for...in循环,类似list或tuple那样,就是必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断的调用迭代对象的__next__()方法,拿到循环的下一个值,直到StopIteration错误时推出循环。

  1. # 以斐波那契数列为例,写一个Fib类
    class Fib:
  2. def __init__(self):
  3. self.a,self.b = 0,1
  4.  
  5. def __iter__(self):
  6. return self
  7.  
  8. def __next__(self):
  9. self.a,self.b = self.b,self.a + self.b # 计算下一个值
  10. if self.a > 100:
  11. raise StopIteration()
  12. return self.a
  13.  
  14. for n in Fib():
  15. print(n)

__getitem__/__setitem__/__delitem__的使用方法

Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行,如果要表现的和list那样按照下标取元素,需要实现__getitem__()方法

  1. class Fib:
  2. def __init__(self):
  3. self.a,self.b = 0,1
  4.  
  5. def __iter__(self):
  6. return self
  7.  
  8. def __next__(self):
  9. self.a,self.b = self.b,self.a + self.b # 计算下一个值
  10. if self.a > 100:
  11. raise StopIteration()
  12. return self.a
  13.  
  14. def __getitem__(self, item):
  15. a,b = 1,1
  16. for x in range(item):
  17. a,b = b,a+b
  18. return a
  19.  
  20. for n in Fib():
  21. print(n)
  22.  
  23. print(Fib()[5]) #
  24. print(Fib()[10]) #

但是list有个神奇的切片方法:

  1. list(range(100))[5:10]

对于Fib却报错,原因是__getitem__()传入的参数可能是一个int,也可以是一个切片对象slice,所以要做判断:

  1. class Fib:
  2. def __getitem__(self, item):
  3. if isinstance(item,int):
  4. a,b = 1,1
  5. for i in range(item):
  6. a,b = b,a+b
  7. return a
  8. if isinstance(item,slice):
  9. start,stop = item.start,item.stop
  10. if start is None:
  11. start = 0
  12. a,b = 1,1
  13. L = []
  14. for x in range(stop):
  15. if x >= start:
  16. L.append(a)
  17. a,b = b,a+b
  18. return L
  19.  
  20. print(Fib()[0,5])

与之对应的是__setitem__()方法,把对象视作list或dict来对集合赋值,最后,还有一个__delitem__()方法,用于删除某个元素

__getattr__/__setattr__/__delattr__

正常情况下我们调用属性或方法不存在时会报错,比如定义Student类:

  1. class Student:
  2. def __init__(self):
  3. self.name = 'Michel'
  4.  
  5. s = Student()
  6. print(s.name)
  7. print(s.age)
  8.  
  9. # Michel
  10. # Traceback (most recent call last):
  11. # File "/Users/qianhaichao/Desktop/Python练习/练习项目/LF-Project/Python练习/廖雪峰Python/面向对象编程.py", line 169, in <module>
  12. # print(s.age)
  13. # AttributeError: 'Student' object has no attribute 'age'

调用name属性,没问题,但是调用不存在的age属性,就有问题了,而且很明显的告诉我们没有找到age这个attribute

要避免这个错误,除了可以加上一个age属性外,Python还有另一个机制,那就是写一个__getattr__()方法,动态的返回一个属性,修改如下:

  1. class Student:
  2. def __init__(self):
  3. self.name = 'Michel'
  4.  
  5. def __getattr__(self, item):
  6. if item == 'age':
  7. return 99
  8.  
  9. s = Student()
  10. print(s.name) # Michel
  11. print(s.age) #

返回函数也是完全可以的

  1. class Student:
  2. def __getattr__(self, item):
  3. if item == 'age':
  4. return lambda: 25
  5.  
  6. s = Student()
  7. print(s.age()) #只是调用方式变了

此外,注意到任意调用如s.abc都会返回None,不会报错,这是因为我们定义了__getattr__默认返回的就是None,要让class只响应特定的几个属性,我们就按照约定,抛出AttributeError的错误:

  1. class Student:
  2. def __getattr__(self, item):
  3. if item == 'age':
  4. return lambda: 25
  5. raise AttributeError('Student object has no attribute %s' % item)

这实际上可以把一个类的所有属性和方法调用全部动态化处理了,不需要做任何特殊手段。

这种完全动态调用的特性有什么实际作用呢?作用就是,可以针对完全动态的情况作调用。

现在很多网站都搞RESTAPI,比如新浪微博、豆瓣啥的,调用API的URL类似:

http://api.server/user/friends

http://api.server/user/timline/list

如果要写SDK,给每个URL对应的API都写一个方法,那得累死,而且API一旦改动,SDK也要改动。

利用完全动态的__getattr__,我们可以写一个链式调用:

  1. class Chain:
  2. def __init__(self,path=''):
  3. self.path = path
  4.  
  5. def __getattr__(self, attr):
  6. return Chain('%s/%s' % (self.path,attr))
  7.  
  8. def __str__(self):
  9. return self.path
  10.  
  11. __repr__ = __str__
  12.  
  13. url = Chain().status.user.timeline.list
  14. print(url) # /status/user/timeline/list

这样,无论API怎么变,SDK都可以根据URL完全动态的调用,而且不随API的增加而改变

__call__的使用

任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用

  1. class Student:
  2. def __init__(self,name):
  3. self.name = name
  4.  
  5. def __call__(self, *args, **kwargs):
  6. print('My name is %s' % self.name)
  7.  
  8. s = Student('XM')
  9. s() # My name is XM

__call__()还可以定义参数,对实例进行直接调用就好比对一个函数进行调用,所以你完全可以把对象看成函数,把函数看成对象,因为这两者之间本来就没啥根本的区别。

怎么判断一个变量是对象还是函数呢?其实更多的时候,我们需要判断一个对象是否能被调用,能被调用的对象就是一个Callable对象,比如函数和我们上面定义的带有__call__()的累实例

  1. class Student:
  2. def __init__(self,name):
  3. self.name = name
  4.  
  5. def __call__(self, *args, **kwargs):
  6. print('My name is %s' % self.name)
  7.  
  8. print(callable(Student('XM'))) # True
  9. print(callable(max)) # True
  10. print(callable([1,2,3])) # False
  11. print(callable('str')) # False

使用枚举类

Python提供了Enum类来实现这个功能:

  1. from enum import Enum
  2.  
  3. Month = Enum('Month',('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
  4.  
  5. for name,member in Month.__members__.items():
  6. print('name:',name,'member:',member,'value:',member.value)
  7.  
  8. print(Month.Jan.value)

value属性则是自动赋给成员的int常量,默认是从1开始计数的。

如果要使用更精确的控制枚举类型,可以从Enum派生出自定义类:

from enum import Enum,unique

  1. from enum import Enum,unique
  2.  
  3. class Weekday(Enum):
  4. Sun = 0 # Sun的value被设定为0
  5. Mon = 1
  6. Tue = 2
  7. Wed = 3
  8. Thu = 4
  9. Fri = 5
  10. Sat = 6
  11. # @unique可以帮助我们检查保证没有重复值
  12.  
  13. day1 = Weekday.Mon
  14.  
  15. print(day1 == Weekday.Mon)

元类的使用(暂且先不研究)

单元测试

我们来编写一个Dict类,这个类的行为和dict一致,但是可以通过属性来访问,用起来就像下面这样:

  1. d = Dict(a=1,b=2)
  2. print(d['a']) #
  3. print(d.a) #

Dict.py代码如下:

  1. class MyDict(dict):
  2.  
  3. def __init__(self,**kw):
  4. super().__init__(**kw)
  5.  
  6. def __getattr__(self, key):
  7. try:
  8. return self[key]
  9. except KeyError:
  10. raise AttributeError('MyDict object has no %s attribute' % key)
  11.  
  12. def __setattr__(self, key, value):
  13. self[key] = value

为了编写单于测试,我们需要引入Python自带的unittest模块,编写TestDict.py如下:

  1. from Dict import MyDict
  2. import unittest
  3.  
  4. class TestDict(unittest.TestCase):
  5.  
  6. def test_init(self):
  7. d = MyDict(a=1,b='test')
  8. self.assertEqual(d.a,1)
  9. self.assertEqual(d.b,'test')
  10. self.assertTrue(isinstance(d,dict))
  11.  
  12. def test_key(self):
  13. d = MyDict()
  14. d['key'] = 'value'
  15. self.assertEqual(d['key'],'value')
  16.  
  17. def test_attr(self):
  18. d = MyDict()
  19. d.key = 'value'
  20. self.assertTrue('key' in d)
  21. self.assertEqual(d['key'],'value')
  22.  
  23. def test_keyerror(self):
  24. d = MyDict()
  25. with self.assertRaises(KeyError):
  26. value = d['empty']
  27.  
  28. def test_attrerror(self):
  29. d = MyDict()
  30. with self.assertRaises(AttributeError):
  31. value = d.empty
  32.  
  33. if __name__ == '__main__':
  34. unittest.main()

setUp与tearDown

可以编写单元测试中编写两个特殊的setUp()和tearDown()方法,这两个方法会分别在没调用一个测试方法的前后分别被执行。

setUp()和tearDown()方法有什么用呢?设想你的测试需要启动一个数据库,这时,就可以在setup()方法中连接数据库,在tearDown()方法中关闭数据库,这样不必在每个测试方法中重复相同的代码:

IO编程

multiprocess模块提供一个一个Process类来代表进程对象,下面的例子演示启动一个子进程并等待其结束:

Process

  1. from multiprocessing import Process
  2. import os
  3.  
  4. def run_proc(name):
  5. print('Run child process %s (%s)' % (name,os.getpid()))
  6.  
  7. if __name__ == '__main__':
  8. print('Parent process %s' % os.getpid())
  9. p = Process(target=run_proc,args=('test',))
  10. print('Child prcess will start')
  11. # 启动子线程
  12. p.start()
  13. # 等待子线程结束后在继续
  14. p.join()
  15. print('Process End')

执行结果如下:

Parent process 27352
Child prcess will start
Run child process test (27353)
Process End

创建子进程时,只需要传入一个执行函数和函数参数,创建一个Process实例,用start()方法启动,这样创建进程比fork()还要简单,join()方法可以等待子线程结束后在继续往下运行,通常用于进程间的同步。

Pool

  1. from multiprocessing import Pool
  2. import os,time,random
  3.  
  4. def long_time_task(name):
  5. print('Run task %s(%s)' % (name,os.getpid()))
  6. start = time.time()
  7. time.sleep(random.random() * 3)
  8. end = time.time()
  9. print('Task %s run %.02f seconds' % (name,(end-start)))
  10.  
  11. if __name__ == '__main__':
  12. print('Parent process %s' % os.getpid())
  13. p = Pool(4)
  14. for i in range(5):
  15. p.apply_async(long_time_task,args=(i,))
  16. print('waitting all subprocesses done')
  17. p.close()
  18. p.join()
  19. print('All subprocesses done.')
  20.  
  21. # 输出结果
  22. # Parent process 27468
  23. # waitting all subprocesses done
  24. # Run task 0(27469)
  25. # Run task 1(27470)
  26. # Run task 2(27471)
  27. # Run task 3(27472)
  28. # Task 3 run 1.03 seconds
  29. # Run task 4(27472)
  30. # Task 2 run 1.27 seconds
  31. # Task 4 run 0.56 seconds
  32. # Task 0 run 2.53 seconds
  33. # Task 1 run 2.96 seconds
  34. # All subprocesses done.

代码解读:

对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须调用close(),调用close()之后就不能继续添加新的Process了。

多线程

Python的标准库提供了两个模块:_thread和threading,_thread是低级模块,threading是高级模块,对_thread进行了封装,绝大多数情况下,我们只需要使用threading这个高级模块、

  1. import threading
  2. import time
  3.  
  4. def loop():
  5. print('Thread %s is running...' % threading.current_thread().name)
  6. n = 0
  7. while n < 5:
  8. n = n + 1
  9. print('Thread %s >>> %s' % (threading.current_thread().name,n))
  10. time.sleep(1)
  11. print('Thread %s end' % threading.current_thread().name)
  12.  
  13. print('Thread %s is running' % threading.current_thread().name)
  14. t = threading.Thread(target=loop,name='LoopThread')
  15. t.start()
  16. t.join()
  17. print('Thread %s end' % threading.current_thread().name)
  18.  
  19. # 输出结果
  20. # Thread MainThread is running
  21. # Thread LoopThread is running...
  22. # Thread LoopThread >>> 1
  23. # Thread LoopThread >>> 2
  24. # Thread LoopThread >>> 3
  25. # Thread LoopThread >>> 4
  26. # Thread LoopThread >>> 5
  27. # Thread LoopThread end
  28. # Thread MainThread end

由于任何进程都有一个默认的线程,我们把这个线程称为主线程,主线程又可以启动新的线程,Python的threading模块有一个current_thread()函数,他永远返回当前线程的实例,主线程实例的名字叫MainThread,子线程的名字在创建是指定,我们用LoopThread命名子线程,名字仅仅在打印时用来显示。、

正则表达式

*表示任意一个字符(包括0个),+表示至少一个字符,?表示0个或者1个字符,用{n}表示n个字符

常用内建模块

datetime

1.获取系统当前时间

  1. from datetime import datetime
  2.  
  3. now = datetime.now()
  4. print(now)
  5. print(type(now))

2.获取指定日期和时间

  1. dt = datetime(2018,5,3,17,9)
  2. print(dt)

3.datetime转换为timestamp

  1. ts = dt.timestamp()
  2. print(ts)
  3.  
  4. ts = now.timestamp()
  5. print(ts)

4.timestamp转换为datetime

  1. ts = 1525338540
  2. dt = datetime.fromtimestamp(ts)
  3. print(dt)

注意到timestamp是一个浮点数,他没有时区的概念,而datetime是有时区的,上述转换是在tiemstamp和本地时间做转换的。

5.timestamp也可以直接被转换为UTC标准时区的时间

  1. dt = datetime.utcfromtimestamp(ts)
  2. print(dt)

6.str转换为datetime

  1. dt = datetime.strptime('2018-05-03 17:30','%Y-%m-%d %H:%M')
  2. print(dt)

7.datetime转换为str

  1. st = datetime.strftime(datetime.now(),'%Y-%m-%d %H:%M')
  2. print(st)

8.datetime的加减

  1. from datetime import datetime,timedelta
  2.  
  3. now = datetime.now()
  4. dt = now + timedelta(hours=10)
  5. print(dt)
  6.  
  7. dt = now + timedelta(days=2,hours=3)
  8. print(dt)

9.时区转换

拿到UTC时间,并强制设置时区为UTC+0:00

  1. utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
  2. print(utc_dt)

astimezone()将时区转换为北京时区

  1. bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
  2. print(bj_dt)

小结:

  datetime表示的时间需要时区信息才能确定一个特定的时间,否则只能视为本地时间

  如果要存储datetime,最佳方法是将其转换为timestamp在存储,因为timestamp的值与时区完全无关

collections

1.namedtuple   namedtuple('名称',[属性list])

  1. from collections import namedtuple
  2.  
  3. Point = namedtuple('Point',['x','y'])
  4. p = Point(1,2)
  5. print(p.x)
  6. print(p.y)

可以根据属性名来访问tuple,使用起来十分方便

2.deque

使用list存储数据的时候,按索引访问元素是很快的,但是插入和删除元素就很慢了,因为list是线性储存,数据量大的时候,插入和删除效率很低。

deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈。

  1. from collections import deque
  2.  
  3. q = deque(['a','b','c','d'])
  4. q.append('x')
  5. q.appendleft('')
  6. print(q)

deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样可以非常高效的往头部添加和删除元素。

3.OrderedDict

使用dict时,key是无序的,在对dict做迭代时,我们无法确定key的顺序,如果要保证key的顺序,可以使用OrderDict:

  1. from collections import OrderedDict
  2.  
  3. d = dict([('a',1),('b',2),('c',3)])
  4. print(d)
  5. d = OrderedDict([('a',1),('b',2),('c',3)])
  6. print(d)

注意:OrderedDict的key会按照插入的顺序排列,不是可以本身排序

OrderedDict可以实现一个FIFO(先进先出)的dict,当容量超出限制时,会删除最早添加的key

4.Counter

统计字符出现的个数:

  1. from collections import Counter
  2.  
  3. c = Counter()
  4. for ch in 'programming':
  5. c[ch] = c[ch] + 1
  6. print(c)

5.Struct

pass

6.hashlib

  1. import hashlib
  2.  
  3. md5 = hashlib.md5()
  4. md5.update('how to use md5 in python hashlib'.encode('utf-8'))
  5. ret = md5.hexdigest()
  6. print(ret)

如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的。

7.itertools

首先看看itertools提供的几个无限迭代器

cycle()传入一个队列,无限循环下去

  1. cs = itertools.cycle('ABC')
  2. for c in cs:
  3. print(c)

repeat()负责把一个元素无限循环下去

  1. ns = itertools.repeat('A',3)
  2. for n in ns:
  3. print(n)

takewhile()根据条件取出有限序列

  1. ns = itertools.count(1)
  2. tw = itertools.takewhile(lambda x: x < 10,ns)
  3. for t in tw:
  4. print(t)

chain()把一组有序队列串联起来,拼成一个更大的队列

  1. ch = itertools.chain('ABC','XYZ')
  2. for c in ch:
  3. print(c)
  4. print(ch)
  5. print(type(ch))

groupby()把序列中相邻且重复的序列跳出来放在一起

  1. gb = itertools.groupby('AABBBCCCADDDBBEEEFF')
  2. for key,group in gb:
  3. print(key,list(group))

HTMLParser

抓取html的商品名称

  1. from html.parser import HTMLParser
  2.  
  3. html_str = '''
  4. <h3 class="tb-main-title" data-title="【金冠现货/全色/顶配版】Xiaomi/小米 小米note移动联通4G手机">
  5. 【金冠现货/全色/顶配版】Xiaomi/小米 小米note移动联通4G手机
  6. </h3>
  7. <p class="tb-subtitle">
  8. 【购机即送布丁套+高清贴膜+线控耳机+剪卡器+电影支架等等,套餐更多豪礼更优惠】 【购机即送布丁套+高清贴膜+线控耳机+剪卡器+电影支架等等,套餐更多豪礼更优惠】 【金冠信誉+顺丰包邮+全国联保---多重保障】
  9. </p>
  10. <div id="J_TEditItem" class="tb-editor-menu"></div>
  11. </div>
  12. <h3 class="tb-main-title" data-title="【现货增强/标准】MIUI/小米 红米手机2红米2移动联通电信4G双卡">
  13. 【现货增强/标准】MIUI/小米 红米手机2红米2移动联通电信4G双卡
  14. </h3>
  15. <p class="tb-subtitle">
  16. [红米手机2代颜色版本较多,请亲们阅读购买说明按需选购---感谢光临] 【金皇冠信誉小米手机集市销量第一】【购买套餐送高清钢化膜+线控通话耳机+ 剪卡器(含还原卡托)+ 防辐射贴+专用高清贴膜+ 擦机布+ 耳机绕线器+手机电影支架+ 一年延保服务+ 默认享受顺丰包邮 !
  17. </p>
  18. <div id="J_TEditItem" class="tb-editor-menu"></div>
  19. </div>
  20. '''
  21.  
  22. # 定义一个MyHTMLParser继承自HTMLParser
  23. class MyHTMLParser(HTMLParser):
  24. re = [] # 放置结果
  25. flag = 0 # 标志是否是我们想要的标签
  26.  
  27. def handle_starttag(self, tag, attrs):
  28. if tag == 'h3':
  29. for attr in attrs:
  30. if attr[0] == 'class' and attr[1] == 'tb-main-title':
  31. self.flag = 1
  32. break
  33. else:
  34. pass
  35.  
  36. def handle_data(self, data):
  37. if self.flag:
  38. self.re.append(data.strip())
  39. self.flag = 0 # 重置标记位
  40. else:
  41. pass
  42.  
  43. myparser = MyHTMLParser()
  44. myparser.feed(html_str)
  45.  
  46. print(myparser.re)

廖雪峰Python电子书总结的更多相关文章

  1. 廖雪峰python教程的第一个疑问

    函数的参数一节中提到: def add_end(L = []); L.append('END') return L 正常调用add_end时(也就是有参数传入时): >>> add_ ...

  2. 廖雪峰Python实战day1

    一.按照廖雪峰的教程,安装开发环境,问题不大. 1.异步框架aiohttp:$pip3 install aiohttp 2.前端模板引擎jinja2:$ pip3 install jinja2 3.安 ...

  3. 【python】廖雪峰python教程学习--基础

     No1: 目前,Python有两个版本,一个是2.x版,一个是3.x版,这两个版本是不兼容的 No2: 用r''表示''内部的字符串默认不转义 No3: 以'''开头,敲回车可以换行 No4: 布尔 ...

  4. 廖雪峰 ---- Python教程

    这是小白的Python新手教程,具有如下特点: 中文,免费,零起点,完整示例,基于最新的Python 3版本. Python是一种计算机程序设计语言.你可能已经听说过很多种流行的编程语言,比如非常难学 ...

  5. 廖雪峰Python学习笔记——类和实例

    Class MyList(list): __metaclass__ = ListMetaclass #它表示在创建MyList这个类时,必须通过 ListMetaclass这个元类的LIstMetac ...

  6. 廖雪峰Python学习笔记——序列化

    序列化 定义:程序运行时所有变量都存在内存中,把变量从内存中变成可存储或可传输的过程称为序列化pickling,在其他语言中称为serialization,marshalling,flattening ...

  7. 廖雪峰Python学习笔记——使用元类

    元类(MetaClasses) 元类提供了一个改变Python类行为的有效方式. 元类的定义是“一个类的类”.任何实例是它自己的类都是元类. class demo(object): pass obj ...

  8. 廖雪峰Python笔记

    △命令行模式和Python交互模式 在Windows开始菜单选择“命令提示符”,就进入到命令行模式,它的提示符类似C:\>:在命令行模式下敲命令python,就看到类似如下的一堆文本输出,然后就 ...

  9. 廖雪峰Python总结5

    1.错误,调试和测试 程序编写造成了bug(必须修复) 用户输入出错(通过检查用户输入) 异常:无法在程序运行过程中预测的.异常是必须被处理的,否则程序会因为各种问题终止并且退出 1.try: try ...

随机推荐

  1. Sass:@error

    @error 和 @warn.@debug 功能是如出一辙. @mixin error($x){ @if $x < 10 { width: $x * 10px; } @else if $x == ...

  2. 在父组件中,直接获取子组件数据-vue

    1.通过 $ref 获取 主父组件中: <x-test ref="ch"></x-test> import XTest from '@/components ...

  3. MAN VGEXTEND

    VGEXTEND(8)                                                        VGEXTEND(8) NAME/名称       vgexten ...

  4. ELK Stack

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11488404.html ELK workflow log -> filebeat -> l ...

  5. 对http的研究

    HTTP 简介 HTTP协议(HyperText Transfer Protocol,超文本传输协议)是因特网上应用最为广泛的一种网络传输协议,所有的WWW文件都必须遵守这个标准. HTTP是一个基于 ...

  6. idhttp.get返回403错误解决办法

    在GET之前,先指定UserAgent参数IdHTTP1.Request.UserAgent := 'Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Ma ...

  7. ES6中的export和import

    1.ES6中的模块加载 ES6 模块是编译时加载,编译时就能确定模块的依赖关系,以及输入和输出的变量,相比于CommonJS 和 AMD 模块都只能在运行时确定输入输出变量的加载效率要高. 1.1.严 ...

  8. kibana使用日志时间进行排序

    kibana默认的是按照客户端的采集时间(@timestamp)进行排序,这往往不是我们所需要的,我们需要的是对日志实际时间进行排序,要解决这个问题,有很多种方法,可以在elasticsearch建立 ...

  9. 使用MAC OS X进行PHP开发的一些建议和技巧

    原创作品,允许转载,转载时请务必以超链接形式标明转载自:线筝 本文链接地址: 使用Mac OS X进行PHP开发的一些建议和技巧 用Mac OS X作为开发机已经有一年多的时间了,在这里写下自己的一些 ...

  10. JavaBean属性和成员变量的区别和联系

    JavaBeans是Java中一种特殊的类,可以将多个对象封装到一个对象(bean)中.特点是可序列化,提供无参构造器,提供getter方法和setter方法访问对象的属性.名称中的“Bean”是用于 ...