题目本身是很常见的,但也容易忽略
math与search方法,最明显的不同,就是匹配规则,match是从字符串第一个位置开始匹配,要求匹配的模式在字符串开始就必须满足,而search是从任意位置开始匹配,只要有满足模式的子字符串即可,如:
text="deabc"
m = re.match(r'(c)', text) # m为None
m = re.search(r'(c)', text) # 匹配成功,返回MatchObject
# match只有在text="cdeab"的情况下,才能匹配情况,必须字符串开头满足模式
Note:
match是作为字符串是否匹配成功的依据,只返回一次匹配结果,要想把所有的匹配结果进行返回,请使用findall
lambda函数是python的匿名函数,不需要使用def关键字进行定义的,它其实一个表达式,并不像函数是语句,lambda函数经常用来表示那些功能简单的函数,由于不需要传递给变量,在内存不存在栈对象,性能相对较好,lambda函数的格式如下:
lambda arg1, arg2, … argN: expression
lambda,经常也用在filter, map, reduce函数中
from functools import reduce
a = [1, 2, 3, 4, 5, 6]
filter_res = filter(lambda x: x % 2 == 0, a)
print([a for a in filter_res]) # [2, 4, 6]
map_res = map(lambda x: x * 2, a)
print([a for a in map_res]) # [2, 4, 6, 8, 10, 12]
reduce_res = reduce(lambda x, y: x + y, a)
print(reduce_res) # 21
笔者这里用的是python3环境,reduce已经被移入functools模块
class Parent(object):
x = 1
class Obj1(Parent):
pass
class Obj2(Parent):
pass
print Parent.x, Obj1.x, Obj2.x
Obj1.x = 2
print Parent.x, Obj1.x, Obj2.x
Parent.x = 3
print Parent.x, Obj1.x, Obj2.x
'''
输出结果为:
1 1 1
1 2 1
3 2 3
'''
看到结果,是不是觉得很诧异,首先x是类变量,属于Parent,打印dir(Obj1)时,你会发现,其实x也是它的属性。Obj1和Obj2都继承于Parent,因此第一行输出全是1。虽然继承Parent,但x其实本质属于Parent,但为啥子类没有却也可以输出值?这是因为,python类机制的原因,当子类不存在x时,它会搜索父类的x。每个类存在mro()的方法或mro魔术特性,可以访问,搜索机制的顺序。
print([x.__name__ for x in Obj1.mro()]) # ['Obj1', 'Parent', 'object']
print([x.__name__ for x in Obj2.__mro__]) # ['Obj2', 'Parent', 'object']
当获取属性或方法时,首先在子类中寻找,子类没有,在父类中寻找,最后是object
当Obj1.x = 2时,子类中存在x,会将2输出,父类中仍然是1, Obj2没有,继续输出父类的
当Parent.x = 3, 输出3 2 3,就会很容易明白了,父类x改变,Obj2输出3,而Obj1存在自己的x,输出2
@print_func_log
def add(x, y):
print(x+y)
首先你得明白什么是装饰函数,装饰函数就是对目的函数进行装饰,在不改变函数时,增加新的东西。如果你需要标记add函数的执行前后,你可能会这样写:
def print_func_log(x, y):
print('function:add' + ' start...')
add(x, y)
print('function:add' + ' end...')
# 这样实现对add函数标记,但是却只能通过执行print_func_log达到目的,当你的app存在存在大量add调用,你都得换成print_func_log
def print_func_log(func):
def wrapper(x, y):
print('function:'+func.__name__ + ' start...')
func(x, y)
print('function:'+func.__name__ + ' end...')
return wrapper
add = print_func_log(add)
add(2, 3)
# 通过返回包装函数,实现对add函数包装,赋予add变量,通过变量执行函数,这样执行的函数就是add,python通过语法糖方式,将print_func_log(add)变为@print_func_log方式
d={},
d[‘a’] = 1
d[‘b’] = 2
d[‘c’] = 3
d.items() =>[(‘a’, 1), (‘b’, 2), (‘c’, 3)]
大家都知道,字典遍历是无序,并不会按添加键值对的顺序遍历,它的底层实现是树,不像列表内存是线性,但是要怎么样保持有序呢?这就需要在添加键值对时,用额外一个列表保持键的顺序,通过键在获取值,如:
d={}
key_list = []
d['a'] = 1
key_list.append('a')
d['b'] = 2
key_list.append('b')
d['c'] = 3
key_list.append('c')
for key in key_list:
print(key, d[key])
# 这种方法是在类外做的,但是题目要求在类中,还要支持所有字典操作,那是不是想到首先定义一个继承字典的类呢,先不慌着写,看看系统为我们提供一个有序字典类,它是怎么样实现的
笔者使用的是python3, OrderedDirc类在collections模块中,使用如下:
from collections import OrderedDict
d = OrderedDict()
d['a'] = 1
d['b'] = 2
d['c'] = 3
print(d.items()) # odict_items([('a', 1), ('b', 2), ('c', 3)])
'''
查看OrderedDict
'Dictionary that remembers insertion order' 记住插入顺序的字典
# An inherited dict maps keys to values. 继承dict
# The inherited dict provides __getitem__, __len__, __contains__, and get.
# The remaining methods are order-aware.
# Big-O running times for all methods are the same as regular dictionaries.
# The internal self.__map dict maps keys to links in a doubly linked list.
内部存在私有变量__map,它是个字典,将key映射为一个双向链表的链接
# The circular doubly linked list starts and ends with a sentinel element.
# The sentinel element never gets deleted (this simplifies the algorithm).
# The sentinel is in self.__hardroot with a weakref proxy in self.__root.
# The prev links are weakref proxies (to prevent circular references).
# Individual links are kept alive by the hard reference in self.__map.
# Those hard references disappear when a key is deleted from an OrderedDict.
'''
查看下源码,没仔细研究,毕竟我还是小白,就先不管牛人的代码,咱们自己实现个简单的,只要是能记住插入顺序的字典就可实现有序字典,现在写个简单demo:
class OrderedDict(dict):
'''
初始化方法,并调用dict方法,使用额外的insert_order记录插入顺序
'''
def __init__(self):
self.insert_order = []
super(OrderedDict, self).__init__()
'''
重写d['a']=1的方法,在插入键值对时,同时记录插入顺序
'''
def __setitem__(self, key, value):
if key not in self.insert_order:
self.insert_order.append(key)
super(OrderedDict, self).__setitem__(key, value)
'''
重写items方法,返回一个有序键值对元组列表
'''
def items(self):
res = []
for key in self.insert_order:
res.append((key, self[key]))
return res
d = OrderedDict()
d['a'] = 1
d['b'] = 2
d['c'] = 3
print(d.items) # [('a', 1), ('b', 2), ('c', 3)]
简单的还是很容易实现,而collections中的OrderedDict相对复杂,在效率上更高
map的使用形式:
map(func, *iterables)
看到这个,觉得是不是就是对迭代对象的回调处理呢,用列表推导式,可以这样表示[func(x) for x in iterables],可以并没有这样简单,下面进行一些map的实践学习:
map对迭代对象处理完,返回一个列表
map(lambda x: x*2, [1, 2, 3, 4]) # [2, 4, 6, 8]
map还可以对多个对象进行并行处理,如:
map(lambda x, y, z: x*100+y*10+z, [1,2,3],[4,5,6],[7,8,9]) # [147, 258, 369]
map是不是很强大,可以对同一索引的元素
依照上面特性,实现自己的一个my_map
'''
当迭代对象多个,长度不同时,获取最短长度的对象
'''
def get_min_iterable_len(iterables):
min_len = len(iterables[0])
for iterable in iterables:
if len(iterable) < min_len:
min_len = len(iterable)
return min_len
'''
获取同索引的一组值
'''
def get_value(iterables, index):
res = []
for iterable in iterables:
res.append(iterable[index])
return res
def my_map(func, *iterables):
if func is None:
pass
if len(iterables) == 0:
pass
min_len = get_min_iterable_len(iterables)
for i in range(min_len):
res = get_value(iterables, i)
'''
这里使用解包,将列表解包传递给函数,因为不确定函数的参数个数,采用yield返回
'''
yield func(*res)
map_res = my_map(lambda x, y: x + y, [1, 2, 3], [3, 4])
print([x for x in map_res])
这个遗憾的是,没采用多线程解决,主要最后获取全部结果时,线程那块我没考虑好