被某些中文教程坑过,我的建议是有问题看官方文档,即使没有很详细的例子,至少不坑
装饰器
毫无疑问在python中用得非常多
1 2 3 4 5 6 7 8 9 10 |
def deco(func): def _deco(): print 'before invoked' func() print 'after invoked' return _deco @deco def f(): print 'f is invoked' |
在f
上加deco
装饰器相当于f = deco(f)
, 和functools.partial
有些类似
如果被装饰的函数f
带参数且有返回值
1 2 3 4 5 6 7 8 9 10 11 12 |
def deco(func): def _deco(*args, **kwargs): print 'before invoked' ret = func(*args, **kwargs) print 'after invoded' return ret return _deco @deco def f(a): print 'f is invoked' return a + 1 |
如果装饰器带有参数,需要多包一层,把参数调用包进去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
def deco(*args): def _deco(func): def __deco(*args, **kwargs): print 'decorator args is', args print 'before invoked' ret = func(*args, **kwargs) print 'after invoded' return ret return __deco return _deco @deco('test') def f(a): print 'f is invoked' return a + 1 |
只有最里面一层的__deco
才会每次都调用,其它外层函数只在包装时调用一次,当然,你可以在其中声明变量,然后拿到__deco
里使用。如果需要保留函数名,则在__deco
上加@functools.wraps
装饰器
使用 类 作装饰器,注意是类此时相当于装饰函数,被装饰的函数会作为实例化参数,得到一个类实例,以python wiki上一个做登录检查的代码为例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class LoginCheck: def __init__(self, f): self._f = f def __call__(self, *args): Status = check_function() if Status is 1: return self._f(*args) else: return alt_function() def check_function(): return test def alt_function(): return 'Sorry - this is the forced behaviour' @LoginCheck def display_members_page(): print 'This is the members page' |
描述器
描述器在监视特定属性的时候很有用,其只在新式类中起作用。所有的描述器协议如下:
descr.__get__(self, obj, type=None) --> value
descr.__set__(self, obj, value) --> None
descr.__delete__(self, obj) --> None
如果一个对象同时定义了 __get__()
和 __set__()
,它叫做资料描述器(data descriptor)。仅定义了 __get__()
的描述器叫非资料描述器
描述器在属性访问时被自动调用。举例来说, obj.x
会在 obj
的字典中找x
,如果x
定义了 __get__
方法,那么 x.__get__(obj)
会依据下面的优先规则被调用
调用优先级:
资料描述器 -> 实例字典 -> 非资料描述器
常用的描述器就是property
了,一般都只实现了__get__
的接口
先给出一个classmethod
的实现和一个用于测试描述器优先级的类
另外如果想在字典中显示展现电影名,方便分析,也可以根据u.item中电影数据,预先生成电影的数据集。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#将id替换为电影名 构造数据集 def loadMovieLens(path='data'): # Get movie titles movies={} for line in open(path+'/u.item'): (id,title)=line.split('|')[0:2] movies[id]=title # Load data prefs={} for line in open(path+'/u.data'): (user,movieid,rating,ts)=line.split('\t') prefs.setdefault(user,{}) prefs[user][movies[movieid]]=float(rating) return prefs |
根据上面两个函数中的一种,到此我们的用户数据集已经构造好了,由于数据量不是非常大,暂时放在内存中即可。
由于以上数据集比较抽象,不方便讲解,至此我们定义一个简单的数据集来讲解一些例子,一个简单的嵌套字典:
1 2 3 4 5 6 7 8 9 10 11 |
#用户:{电影名称:评分} critics={ 'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5,'The Night Listener': 3.0}, 'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0,'You, Me and Dupree': 3.5}, 'Michael Phillips':{'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,'Superman Returns': 3.5, 'The Night Listener': 4.0}, 'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0,'The Night Listener': 4.5, 'Superman Returns': 4.0,'You, Me and Dupree': 2.5}, 'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0, 'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0, 'You, Me and Dupree': 2.0}, 'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5}, 'Toby': {'Snakes on a Plane':4.5,'You, Me and Dupree':1.0,'Superman Returns':4.0} } |
寻找相近用户
收集完用户信息后,我们通过一些方法来确定两个用户之间品味的相似程度,计算他们的相似度评价值。有很多方法可以计算,我们在此介绍两套常见的方法:欧几里得距离和皮尔逊相关度。
欧几里得距离
欧几里得距离(euclidea nmetric)(也称欧式距离)是一个通常采用的距离定义,指在m维空间中两个点之间的真实距离,或者向量的自然长度(即该点到原点的距离)。在二维和三维空间中的欧氏距离就是两点之间的实际距离。
数学定义:
已知两点 A = (x_1,x_2,…,x_n)和B = (y_1,y_2,…,y_n),则两点间距离:
接下来我们只要把数据集映射为坐标系就可以明显的比较出相似度,以”Snakes on a Plane”和”You, Me and Dupree”两部电影距离,有坐标系如下图:
计算上图中Toby和Mick LaSalle的相似度:
from math import sqrt
sqrt(pow( 4.5-4 , 2 ) + pow( 1 – 2 , 2))
1.118033988749895
上面的式子计算出了实际距离值,但在实际应用中,我们希望相似度越大返回的值越大,并且控制在0~1之间的值。为此,我们可以取函数值加1的倒数(加1是为了防止除0的情况):
1/(1+sqrt(pow( 4.5-4 , 2 ) + pow( 1 – 2 , 2)))
0.4721359549995794
接下来我们就可以封装一个基于欧几里得距离的相似度评价,具体python实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#欧几里得距离 def sim_distance( prefs,person1,person2 ): si={} for itemId in prefs[person1]: if itemId in prefs[person2]: si[itemId] = 1 #no same item if len(si)==0: return 0 sum_of_squares = 0.0 #计算距离 |