廖雪峰Python电子书总结
函数
1.注意:函数的默认参数必须指向不可变对象
未修改前:
- def add_end(L=[]):
- L.append('END')
- return L
存在的问题:如果连续调用多次,会出现多个 'END' 对象
原因解释:
Python函数在定义的时候,默认参数L就被计算出来了,即 [] ,因为默认参数L指向了可变对象[],每次调用的时候,如果改变了L的内容,下次调用的时候,L指向的内容也发生了改变,不再是函数定义时候的 [] 了。
修改后:
- def add_end(L=None):
- if L is None:
- L = []
- L.append('END')
- return L
这样无论调用多少次都不会出问题。
2.关键字参数
func(xx,xxx,**kw)
- def person(name,age,**kw):
- print('name:',name,'age:',age,'other:',kw)
- extra = {'city': 'BeiJing','job': 'Python'}
- person('XM',23,**extra)
- # 输出
- # 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对象
- >>> from collections import Iterator
- >>> isinstance((x * x for x in range(10)),Iterator)
- True
- >>> isinstance([],Iterator)
- False
- >>> isinstance({},Iterator)
- False
生成器都是Iterator对象,但是list、dict、str、虽然是Iterable,却不是Iterator。
把list、dict、str等Iterable变成Iterator,可以使用iter()函数
- >>> isinstance(iter([]),Iterator)
- True
- >>> isinstance(iter({}),Iterator)
- True
函数式编程
fitler用法
把一个序列中的空字符串删掉
- # 1.把一个序列中的空字符串删掉
- def not_empty(s):
- return s and s.strip()
- li = ['A','',None,'B',' ','C']
- li = list(filter(not_empty,li))
- print(li)
闭包
返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量
- # 返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量
- def count():
- fs = []
- for i in range(1,4):
- def f():
- return i * i
- fs.append(f)
- return fs
- f1,f2,f3 = count()
- print(f1()) # 输出9
- print(f2()) # 输出9
- print(f3()) # 输出9
- # 原因就在于返回的函数引用了变量i,但它并非立刻执行,等到3个函数都返回时,他们所引用的变量i,已经变成了3
# 因此最终结果都为9- # 如果一定要引用循环变量怎么办?方法就是在创建一个函数,用该函数的参数绑定循环变量当前的值,无论循环变量后期如何变化
- # 已绑定到函数参数的值不变
- def count():
- def f(j):
- def g():
- return j * j
- return g
- fs = []
- for i in range(1,4):
- fs.append(f(i))
- return fs
- f1,f2,f3 = count()
- print(f1()) # 输出1
- print(f2()) # 输出4
- print(f3()) # 输出9
装饰器
- # 定义装饰器
- def log(func):
- def wrapper(*args,**kwargs):
- print('call %s()' % func.__name__)
- func(*args,**kwargs)
- return wrapper
- @log
- def now():
- print('2018-04-25')
- # 调用now函数
- now()
- # 输出
- # call now()
- # 2018-04-25
解释:把@log放到now()函数定义处,相当于执行了语句
now = log(now)
由于log()是一个decorator,返回一个函数,所以原来的now()函数仍然存在,只是现在同名的now()指向了新的函数,于是调用now()将执行新的函数,即在log()函数中返回的wrapper()函数
如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数
- def log(txt):
- def decorator(func):
- def warpper(*args,**kwargs):
- print('%s %s' % (txt,func.__name__))
- return func(*args,**kwargs)
- return warpper
- return decorator
- @log('execute')
- def now():
- print('2018-04-25')
- # 调用now()函数
- now()
- print('%s' % now.__name__)
- # 输出
- # execute now
- # 2018-04-25
- # 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的写法如下:
- from functools import wraps
- def log(func):
- @wraps(func)
- def wrapper(*args,**kwargs):
- print('call %s' % func.__name__)
- return func(*args,**kwargs)
- return wrapper
- @log
- def now():
- print('2018-04-25')
- # 调用函数
- now()
- print(now.__name__)
- # 输出
- # call now
- # 2018-04-25
- # now
- def log(txt):
- def decorator(func):
- @wraps(func)
- def wrapper(*args,**kwargs):
- print('%s %s' % (txt,func.__name__))
- return func(*args,**kwargs)
- return wrapper
- return decorator
- @log('execute')
- def now():
- print('2018-04-25')
- # 调用函数
- now()
- print(now.__name__)
- # 输出
- # execute now
- # 2018-04-25
- # now
偏函数
通过functools.partial可以帮助我们创建一个偏函数
- from functools import partial
- int2 = partial(int,base=2)
- ret = int2('')
- print(ret)
- # 输出
- #
- max2 = partial(max,10)
- ret = max2(2,3,4)
- print(ret)
- # 输出
- #
简单总结functools.partial的作用,就是把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新的函数会更简单
面向对象编程
需要注意的是,在Python中,变量名类似__xxx__的,也就是双下划线开头,双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以不能用__name__、__score__这样的变量名
双下划线开头的实例变量是不是就不能被外部访问了?其实不是的,不能只能访问__name是因为Python解释器对外吧__name变量改成了_Student__name,所以可以通过_Student__name来访问__name变量:
bart._Student__name
但是强烈不推荐这么做,因为不同版本的Python解释器可能会把__name改成不同的变量名
如何判断一个对象是否是函数怎么办?可以使用types模块中定义的常量:
- import types
- def Animals():
- pass
- a = Animals()
- print(type(Animals) == types.FunctionType)
如何给实例绑定一个方法?
- class Student():
- pass
- def set_age(self,age): # 定义一个函数作为实例方法
- self.age = age
- s = Student()
- from types import MethodType
- s.set_age = MethodType(set_age,s) # 给实例绑定一个方法
- s.set_age(25) # 调用实例方法
- print(s.age) # 测试结果
为了给所有实例都绑定方法,可以给class绑定方法:
- Student.set_age = MethodType(set_age,Student)
- s1 = Student()
- s1.set_age(12)
- print(s1.age)
- s2 = Student()
- s2.set_age(23)
- print(s2.age)
__slots__的使用
如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加name和age属性。
为了达到目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:
- class Student:
- __slots__ = ('name','age') # 用tuple定义绑定的属性名称
- s = Student()
- s.name = 'XM'
- s.age = 34
- s.score = 98 # 绑定属性score 报错
- # AttributeError: 'Student' object has no attribute 'score'
除非在子类中也定义__slots__,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__
- class GraduateStudent(Student):
- __slots__ = ('score') # 除非子类也定义__slots__,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__
- pass
- g = GraduateStudent()
- g.score = 97
- g.name = 'DN'
@property的使用
- class Student:
- @property
- def score(self):
- return self._score
- @score.setter
- def score(self,value):
- if not isinstance(value,int):
- raise ValueError('score must be int')
- if value < 0 or value >100:
- raise ValueError('score must be 0~100')
- self._score = value
- s = Student()
- s.score = 90
- print(s.score)
注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴漏的,而是通过getter和setter方法实现的。还可以设置只读属性,不定义setter方法就是只读属性
__str__和__repr__的区别?
在不使用print的时候,直接显示变量的调用的不是__str__(),而是__repr__(),两者的区别是__str__()返回用看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为了调试服务的。
偷懒的写法是
- class Student:
- def __init__(self,name):
- self.name = name
- def __str__(self):
- print('Student object(name = %s)' % self.name)
- __repr__ = __str__
__iter__
如果一个类想被用于for...in循环,类似list或tuple那样,就是必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断的调用迭代对象的__next__()方法,拿到循环的下一个值,直到StopIteration错误时推出循环。
- # 以斐波那契数列为例,写一个Fib类
class Fib:- def __init__(self):
- self.a,self.b = 0,1
- def __iter__(self):
- return self
- def __next__(self):
- self.a,self.b = self.b,self.a + self.b # 计算下一个值
- if self.a > 100:
- raise StopIteration()
- return self.a
- for n in Fib():
- print(n)
__getitem__/__setitem__/__delitem__的使用方法
Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行,如果要表现的和list那样按照下标取元素,需要实现__getitem__()方法
- class Fib:
- def __init__(self):
- self.a,self.b = 0,1
- def __iter__(self):
- return self
- def __next__(self):
- self.a,self.b = self.b,self.a + self.b # 计算下一个值
- if self.a > 100:
- raise StopIteration()
- return self.a
- def __getitem__(self, item):
- a,b = 1,1
- for x in range(item):
- a,b = b,a+b
- return a
- for n in Fib():
- print(n)
- print(Fib()[5]) #
- print(Fib()[10]) #
但是list有个神奇的切片方法:
- list(range(100))[5:10]
对于Fib却报错,原因是__getitem__()传入的参数可能是一个int,也可以是一个切片对象slice,所以要做判断:
- class Fib:
- def __getitem__(self, item):
- if isinstance(item,int):
- a,b = 1,1
- for i in range(item):
- a,b = b,a+b
- return a
- if isinstance(item,slice):
- start,stop = item.start,item.stop
- if start is None:
- start = 0
- a,b = 1,1
- L = []
- for x in range(stop):
- if x >= start:
- L.append(a)
- a,b = b,a+b
- return L
- print(Fib()[0,5])
与之对应的是__setitem__()方法,把对象视作list或dict来对集合赋值,最后,还有一个__delitem__()方法,用于删除某个元素
__getattr__/__setattr__/__delattr__
正常情况下我们调用属性或方法不存在时会报错,比如定义Student类:
- class Student:
- def __init__(self):
- self.name = 'Michel'
- s = Student()
- print(s.name)
- print(s.age)
- # Michel
- # Traceback (most recent call last):
- # File "/Users/qianhaichao/Desktop/Python练习/练习项目/LF-Project/Python练习/廖雪峰Python/面向对象编程.py", line 169, in <module>
- # print(s.age)
- # AttributeError: 'Student' object has no attribute 'age'
调用name属性,没问题,但是调用不存在的age属性,就有问题了,而且很明显的告诉我们没有找到age这个attribute
要避免这个错误,除了可以加上一个age属性外,Python还有另一个机制,那就是写一个__getattr__()方法,动态的返回一个属性,修改如下:
- class Student:
- def __init__(self):
- self.name = 'Michel'
- def __getattr__(self, item):
- if item == 'age':
- return 99
- s = Student()
- print(s.name) # Michel
- print(s.age) #
返回函数也是完全可以的
- class Student:
- def __getattr__(self, item):
- if item == 'age':
- return lambda: 25
- s = Student()
- print(s.age()) #只是调用方式变了
此外,注意到任意调用如s.abc都会返回None,不会报错,这是因为我们定义了__getattr__默认返回的就是None,要让class只响应特定的几个属性,我们就按照约定,抛出AttributeError的错误:
- class Student:
- def __getattr__(self, item):
- if item == 'age':
- return lambda: 25
- 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__,我们可以写一个链式调用:
- class Chain:
- def __init__(self,path=''):
- self.path = path
- def __getattr__(self, attr):
- return Chain('%s/%s' % (self.path,attr))
- def __str__(self):
- return self.path
- __repr__ = __str__
- url = Chain().status.user.timeline.list
- print(url) # /status/user/timeline/list
这样,无论API怎么变,SDK都可以根据URL完全动态的调用,而且不随API的增加而改变
__call__的使用
任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用
- class Student:
- def __init__(self,name):
- self.name = name
- def __call__(self, *args, **kwargs):
- print('My name is %s' % self.name)
- s = Student('XM')
- s() # My name is XM
__call__()还可以定义参数,对实例进行直接调用就好比对一个函数进行调用,所以你完全可以把对象看成函数,把函数看成对象,因为这两者之间本来就没啥根本的区别。
怎么判断一个变量是对象还是函数呢?其实更多的时候,我们需要判断一个对象是否能被调用,能被调用的对象就是一个Callable对象,比如函数和我们上面定义的带有__call__()的累实例
- class Student:
- def __init__(self,name):
- self.name = name
- def __call__(self, *args, **kwargs):
- print('My name is %s' % self.name)
- print(callable(Student('XM'))) # True
- print(callable(max)) # True
- print(callable([1,2,3])) # False
- print(callable('str')) # False
使用枚举类
Python提供了Enum类来实现这个功能:
- from enum import Enum
- Month = Enum('Month',('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
- for name,member in Month.__members__.items():
- print('name:',name,'member:',member,'value:',member.value)
- print(Month.Jan.value)
value属性则是自动赋给成员的int常量,默认是从1开始计数的。
如果要使用更精确的控制枚举类型,可以从Enum派生出自定义类:
from enum import Enum,unique
- from enum import Enum,unique
- class Weekday(Enum):
- Sun = 0 # Sun的value被设定为0
- Mon = 1
- Tue = 2
- Wed = 3
- Thu = 4
- Fri = 5
- Sat = 6
- # @unique可以帮助我们检查保证没有重复值
- day1 = Weekday.Mon
- print(day1 == Weekday.Mon)
元类的使用(暂且先不研究)
单元测试
我们来编写一个Dict类,这个类的行为和dict一致,但是可以通过属性来访问,用起来就像下面这样:
- d = Dict(a=1,b=2)
- print(d['a']) #
- print(d.a) #
Dict.py代码如下:
- class MyDict(dict):
- def __init__(self,**kw):
- super().__init__(**kw)
- def __getattr__(self, key):
- try:
- return self[key]
- except KeyError:
- raise AttributeError('MyDict object has no %s attribute' % key)
- def __setattr__(self, key, value):
- self[key] = value
为了编写单于测试,我们需要引入Python自带的unittest模块,编写TestDict.py如下:
- from Dict import MyDict
- import unittest
- class TestDict(unittest.TestCase):
- def test_init(self):
- d = MyDict(a=1,b='test')
- self.assertEqual(d.a,1)
- self.assertEqual(d.b,'test')
- self.assertTrue(isinstance(d,dict))
- def test_key(self):
- d = MyDict()
- d['key'] = 'value'
- self.assertEqual(d['key'],'value')
- def test_attr(self):
- d = MyDict()
- d.key = 'value'
- self.assertTrue('key' in d)
- self.assertEqual(d['key'],'value')
- def test_keyerror(self):
- d = MyDict()
- with self.assertRaises(KeyError):
- value = d['empty']
- def test_attrerror(self):
- d = MyDict()
- with self.assertRaises(AttributeError):
- value = d.empty
- if __name__ == '__main__':
- unittest.main()
setUp与tearDown
可以编写单元测试中编写两个特殊的setUp()和tearDown()方法,这两个方法会分别在没调用一个测试方法的前后分别被执行。
setUp()和tearDown()方法有什么用呢?设想你的测试需要启动一个数据库,这时,就可以在setup()方法中连接数据库,在tearDown()方法中关闭数据库,这样不必在每个测试方法中重复相同的代码:
IO编程
multiprocess模块提供一个一个Process类来代表进程对象,下面的例子演示启动一个子进程并等待其结束:
Process
- 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('Child prcess will start')
- # 启动子线程
- p.start()
- # 等待子线程结束后在继续
- p.join()
- print('Process End')
执行结果如下:
Parent process 27352
Child prcess will start
Run child process test (27353)
Process End
创建子进程时,只需要传入一个执行函数和函数参数,创建一个Process实例,用start()方法启动,这样创建进程比fork()还要简单,join()方法可以等待子线程结束后在继续往下运行,通常用于进程间的同步。
Pool
- 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 run %.02f seconds' % (name,(end-start)))
- if __name__ == '__main__':
- print('Parent process %s' % os.getpid())
- p = Pool(4)
- for i in range(5):
- p.apply_async(long_time_task,args=(i,))
- print('waitting all subprocesses done')
- p.close()
- p.join()
- print('All subprocesses done.')
- # 输出结果
- # Parent process 27468
- # waitting all subprocesses done
- # Run task 0(27469)
- # Run task 1(27470)
- # Run task 2(27471)
- # Run task 3(27472)
- # Task 3 run 1.03 seconds
- # Run task 4(27472)
- # Task 2 run 1.27 seconds
- # Task 4 run 0.56 seconds
- # Task 0 run 2.53 seconds
- # Task 1 run 2.96 seconds
- # All subprocesses done.
代码解读:
对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须调用close(),调用close()之后就不能继续添加新的Process了。
多线程
Python的标准库提供了两个模块:_thread和threading,_thread是低级模块,threading是高级模块,对_thread进行了封装,绝大多数情况下,我们只需要使用threading这个高级模块、
- import threading
- import time
- def loop():
- print('Thread %s is running...' % threading.current_thread().name)
- n = 0
- while n < 5:
- n = n + 1
- print('Thread %s >>> %s' % (threading.current_thread().name,n))
- time.sleep(1)
- print('Thread %s end' % threading.current_thread().name)
- print('Thread %s is running' % threading.current_thread().name)
- t = threading.Thread(target=loop,name='LoopThread')
- t.start()
- t.join()
- print('Thread %s end' % threading.current_thread().name)
- # 输出结果
- # Thread MainThread is running
- # Thread LoopThread is running...
- # Thread LoopThread >>> 1
- # Thread LoopThread >>> 2
- # Thread LoopThread >>> 3
- # Thread LoopThread >>> 4
- # Thread LoopThread >>> 5
- # Thread LoopThread end
- # Thread MainThread end
由于任何进程都有一个默认的线程,我们把这个线程称为主线程,主线程又可以启动新的线程,Python的threading模块有一个current_thread()函数,他永远返回当前线程的实例,主线程实例的名字叫MainThread,子线程的名字在创建是指定,我们用LoopThread命名子线程,名字仅仅在打印时用来显示。、
正则表达式
*表示任意一个字符(包括0个),+表示至少一个字符,?表示0个或者1个字符,用{n}表示n个字符
常用内建模块
datetime
1.获取系统当前时间
- from datetime import datetime
- now = datetime.now()
- print(now)
- print(type(now))
2.获取指定日期和时间
- dt = datetime(2018,5,3,17,9)
- print(dt)
3.datetime转换为timestamp
- ts = dt.timestamp()
- print(ts)
- ts = now.timestamp()
- print(ts)
4.timestamp转换为datetime
- ts = 1525338540
- dt = datetime.fromtimestamp(ts)
- print(dt)
注意到timestamp是一个浮点数,他没有时区的概念,而datetime是有时区的,上述转换是在tiemstamp和本地时间做转换的。
5.timestamp也可以直接被转换为UTC标准时区的时间
- dt = datetime.utcfromtimestamp(ts)
- print(dt)
6.str转换为datetime
- dt = datetime.strptime('2018-05-03 17:30','%Y-%m-%d %H:%M')
- print(dt)
7.datetime转换为str
- st = datetime.strftime(datetime.now(),'%Y-%m-%d %H:%M')
- print(st)
8.datetime的加减
- from datetime import datetime,timedelta
- now = datetime.now()
- dt = now + timedelta(hours=10)
- print(dt)
- dt = now + timedelta(days=2,hours=3)
- print(dt)
9.时区转换
拿到UTC时间,并强制设置时区为UTC+0:00
- utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
- print(utc_dt)
astimezone()将时区转换为北京时区
- bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
- print(bj_dt)
小结:
datetime表示的时间需要时区信息才能确定一个特定的时间,否则只能视为本地时间
如果要存储datetime,最佳方法是将其转换为timestamp在存储,因为timestamp的值与时区完全无关
collections
1.namedtuple namedtuple('名称',[属性list])
- from collections import namedtuple
- Point = namedtuple('Point',['x','y'])
- p = Point(1,2)
- print(p.x)
- print(p.y)
可以根据属性名来访问tuple,使用起来十分方便
2.deque
使用list存储数据的时候,按索引访问元素是很快的,但是插入和删除元素就很慢了,因为list是线性储存,数据量大的时候,插入和删除效率很低。
deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈。
- from collections import deque
- q = deque(['a','b','c','d'])
- q.append('x')
- q.appendleft('')
- print(q)
deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样可以非常高效的往头部添加和删除元素。
3.OrderedDict
使用dict时,key是无序的,在对dict做迭代时,我们无法确定key的顺序,如果要保证key的顺序,可以使用OrderDict:
- from collections import OrderedDict
- d = dict([('a',1),('b',2),('c',3)])
- print(d)
- d = OrderedDict([('a',1),('b',2),('c',3)])
- print(d)
注意:OrderedDict的key会按照插入的顺序排列,不是可以本身排序
OrderedDict可以实现一个FIFO(先进先出)的dict,当容量超出限制时,会删除最早添加的key
4.Counter
统计字符出现的个数:
- from collections import Counter
- c = Counter()
- for ch in 'programming':
- c[ch] = c[ch] + 1
- print(c)
5.Struct
pass
6.hashlib
- import hashlib
- md5 = hashlib.md5()
- md5.update('how to use md5 in python hashlib'.encode('utf-8'))
- ret = md5.hexdigest()
- print(ret)
如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的。
7.itertools
首先看看itertools提供的几个无限迭代器
cycle()传入一个队列,无限循环下去
- cs = itertools.cycle('ABC')
- for c in cs:
- print(c)
repeat()负责把一个元素无限循环下去
- ns = itertools.repeat('A',3)
- for n in ns:
- print(n)
takewhile()根据条件取出有限序列
- ns = itertools.count(1)
- tw = itertools.takewhile(lambda x: x < 10,ns)
- for t in tw:
- print(t)
chain()把一组有序队列串联起来,拼成一个更大的队列
- ch = itertools.chain('ABC','XYZ')
- for c in ch:
- print(c)
- print(ch)
- print(type(ch))
groupby()把序列中相邻且重复的序列跳出来放在一起
- gb = itertools.groupby('AABBBCCCADDDBBEEEFF')
- for key,group in gb:
- print(key,list(group))
HTMLParser
抓取html的商品名称
- from html.parser import HTMLParser
- html_str = '''
- <h3 class="tb-main-title" data-title="【金冠现货/全色/顶配版】Xiaomi/小米 小米note移动联通4G手机">
- 【金冠现货/全色/顶配版】Xiaomi/小米 小米note移动联通4G手机
- </h3>
- <p class="tb-subtitle">
- 【购机即送布丁套+高清贴膜+线控耳机+剪卡器+电影支架等等,套餐更多豪礼更优惠】 【购机即送布丁套+高清贴膜+线控耳机+剪卡器+电影支架等等,套餐更多豪礼更优惠】 【金冠信誉+顺丰包邮+全国联保---多重保障】
- </p>
- <div id="J_TEditItem" class="tb-editor-menu"></div>
- </div>
- <h3 class="tb-main-title" data-title="【现货增强/标准】MIUI/小米 红米手机2红米2移动联通电信4G双卡">
- 【现货增强/标准】MIUI/小米 红米手机2红米2移动联通电信4G双卡
- </h3>
- <p class="tb-subtitle">
- [红米手机2代颜色版本较多,请亲们阅读购买说明按需选购---感谢光临] 【金皇冠信誉小米手机集市销量第一】【购买套餐送高清钢化膜+线控通话耳机+ 剪卡器(含还原卡托)+ 防辐射贴+专用高清贴膜+ 擦机布+ 耳机绕线器+手机电影支架+ 一年延保服务+ 默认享受顺丰包邮 !
- </p>
- <div id="J_TEditItem" class="tb-editor-menu"></div>
- </div>
- '''
- # 定义一个MyHTMLParser继承自HTMLParser
- class MyHTMLParser(HTMLParser):
- re = [] # 放置结果
- flag = 0 # 标志是否是我们想要的标签
- def handle_starttag(self, tag, attrs):
- if tag == 'h3':
- for attr in attrs:
- if attr[0] == 'class' and attr[1] == 'tb-main-title':
- self.flag = 1
- break
- else:
- pass
- def handle_data(self, data):
- if self.flag:
- self.re.append(data.strip())
- self.flag = 0 # 重置标记位
- else:
- pass
- myparser = MyHTMLParser()
- myparser.feed(html_str)
- print(myparser.re)
廖雪峰Python电子书总结的更多相关文章
- 廖雪峰python教程的第一个疑问
函数的参数一节中提到: def add_end(L = []); L.append('END') return L 正常调用add_end时(也就是有参数传入时): >>> add_ ...
- 廖雪峰Python实战day1
一.按照廖雪峰的教程,安装开发环境,问题不大. 1.异步框架aiohttp:$pip3 install aiohttp 2.前端模板引擎jinja2:$ pip3 install jinja2 3.安 ...
- 【python】廖雪峰python教程学习--基础
No1: 目前,Python有两个版本,一个是2.x版,一个是3.x版,这两个版本是不兼容的 No2: 用r''表示''内部的字符串默认不转义 No3: 以'''开头,敲回车可以换行 No4: 布尔 ...
- 廖雪峰 ---- Python教程
这是小白的Python新手教程,具有如下特点: 中文,免费,零起点,完整示例,基于最新的Python 3版本. Python是一种计算机程序设计语言.你可能已经听说过很多种流行的编程语言,比如非常难学 ...
- 廖雪峰Python学习笔记——类和实例
Class MyList(list): __metaclass__ = ListMetaclass #它表示在创建MyList这个类时,必须通过 ListMetaclass这个元类的LIstMetac ...
- 廖雪峰Python学习笔记——序列化
序列化 定义:程序运行时所有变量都存在内存中,把变量从内存中变成可存储或可传输的过程称为序列化pickling,在其他语言中称为serialization,marshalling,flattening ...
- 廖雪峰Python学习笔记——使用元类
元类(MetaClasses) 元类提供了一个改变Python类行为的有效方式. 元类的定义是“一个类的类”.任何实例是它自己的类都是元类. class demo(object): pass obj ...
- 廖雪峰Python笔记
△命令行模式和Python交互模式 在Windows开始菜单选择“命令提示符”,就进入到命令行模式,它的提示符类似C:\>:在命令行模式下敲命令python,就看到类似如下的一堆文本输出,然后就 ...
- 廖雪峰Python总结5
1.错误,调试和测试 程序编写造成了bug(必须修复) 用户输入出错(通过检查用户输入) 异常:无法在程序运行过程中预测的.异常是必须被处理的,否则程序会因为各种问题终止并且退出 1.try: try ...
随机推荐
- Sass:@error
@error 和 @warn.@debug 功能是如出一辙. @mixin error($x){ @if $x < 10 { width: $x * 10px; } @else if $x == ...
- 在父组件中,直接获取子组件数据-vue
1.通过 $ref 获取 主父组件中: <x-test ref="ch"></x-test> import XTest from '@/components ...
- MAN VGEXTEND
VGEXTEND(8) VGEXTEND(8) NAME/名称 vgexten ...
- ELK Stack
原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11488404.html ELK workflow log -> filebeat -> l ...
- 对http的研究
HTTP 简介 HTTP协议(HyperText Transfer Protocol,超文本传输协议)是因特网上应用最为广泛的一种网络传输协议,所有的WWW文件都必须遵守这个标准. HTTP是一个基于 ...
- idhttp.get返回403错误解决办法
在GET之前,先指定UserAgent参数IdHTTP1.Request.UserAgent := 'Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Ma ...
- ES6中的export和import
1.ES6中的模块加载 ES6 模块是编译时加载,编译时就能确定模块的依赖关系,以及输入和输出的变量,相比于CommonJS 和 AMD 模块都只能在运行时确定输入输出变量的加载效率要高. 1.1.严 ...
- kibana使用日志时间进行排序
kibana默认的是按照客户端的采集时间(@timestamp)进行排序,这往往不是我们所需要的,我们需要的是对日志实际时间进行排序,要解决这个问题,有很多种方法,可以在elasticsearch建立 ...
- 使用MAC OS X进行PHP开发的一些建议和技巧
原创作品,允许转载,转载时请务必以超链接形式标明转载自:线筝 本文链接地址: 使用Mac OS X进行PHP开发的一些建议和技巧 用Mac OS X作为开发机已经有一年多的时间了,在这里写下自己的一些 ...
- JavaBean属性和成员变量的区别和联系
JavaBeans是Java中一种特殊的类,可以将多个对象封装到一个对象(bean)中.特点是可序列化,提供无参构造器,提供getter方法和setter方法访问对象的属性.名称中的“Bean”是用于 ...