廖雪峰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 ...
随机推荐
- JS基础入门篇(三)— for循环,取余,取整。
1.for循环 1.for的基本简介 作用: 根据一定的条件,重复地执行一行或多行代码 语法: for( 初始化 ; 判断条件 ; 条件改变 ){ 代码块 } 2.for循环的执行顺序 <bod ...
- 黑客教父郭盛华:提升家庭WiFi的10个方法
中国黑客教父,知名网络安全专家郭盛华曾发博文表示:“WiFi是互联网发展过程中最重要的发展之一,虚拟世界没有百分百的安全,所以杀毒软件并不可以抵抗全部的黑客攻击.“ 用户WiFi密码尽量不要使用简单单 ...
- Js中window.location.href和window.location.replace的区别
href相当于打开一个新页面,replace相当于替换当前页面:这里打开页面都是针对历史记录来说,在页面上看完全相同,只是浏览器的history表现不同如果在1.html中点击链接到2.html,然后 ...
- 【ElasticSearch】概念
小史是一个非科班的程序员,虽然学的是电子专业,但是通过自己的努力成功通过了面试,现在要开始迎接新生活了. 对小史面试情况感兴趣的同学可以观看面试现场系列. 随着央视诗词大会的热播,小史开始对诗词感兴趣 ...
- 项目部署到tomcat,浏览器能够访问,手机不能访问。
问题:有这样一个问题,把项目部署到tomcat上,浏览器能够访问,但是手机不能访问. 解决:在 tomcat中找到conf文件夹,然后找到web.xml
- 前端开发本地存储之cookie
1.cookie cookie是纯文本,没有可执行代码,是指某些网站为了辨别用户身份.进行 session 跟踪而储存在用户本地终端(浏览器)上的数据(通常经过加密).当用户访问了某个网站的时候,我们 ...
- 「THUPC 2017」机场 / Airport
https://loj.ac/problem/2403 题解 神仙题. 练习赛的时候想了个假建图. 正解太神仙了. 先把不合法情况判掉. 先对时间离散化,每个时间点开一个点. 然后把他们一次串起来,中 ...
- 学习笔记11 EF查询相当于sql 中的 where in
两种写法 1. int[] Ids={1,2,3} DBContainer db=new DBContainer(); var list=db.表明.where(a=>Ids.Contains( ...
- 一些比较好的blogs
01Trie水过普通平衡树 MinMax容斥 Trie与可持久化Trie 圆方树 CDQ分治 网络流 有上下界的网络流 Mobius函数 组合数学盒子小球 dsu on tree VFK大爷的反演课件 ...
- OSI参考模型和网络排错
OSI七层协议 应用层 应用程序通信服务 表示层 显示 加密 数据格式 会话层 服务器和客户机建立会话 netstat -nb 查看会话 mscofig 传输层 可靠回话传输 分段 ...