目录
一、表示修饰符/装饰器。
可以在模块或者类的定义层内对函数进行修饰。出现在函数定义的前一行,不允许和函数定义在同一行。
一个@修饰符就是一个函数【格式:@修饰名】,它将被修饰的函数作为参数,并返回修饰后的同名函数或其他可调用的东西(如果返回不是一个可调用的对象那么会报错)。可在代码运行期间动态增加功能。本质上,decorator 就是一个返回函数的高阶函数
会直接执行函数。即可等价替换为: 修饰名(被修饰函数())
例1:
def funA(desA):
print("It's funA")
def funB(desB):
print("It's funB")
@funA
def funC():
print("It's funC")
运行结果:
It's funA
例2:
可以看出,该例子中@test等价于 test(xxx()),但是这种写法你得考虑python代码的执行顺序。
def test(func):
print("a")
return func()
@test
def xxx():
print('Hello world!')
运行结果:
a
Hello world!
例3:
为更深刻理解该用法,来个复杂点的嵌套型。
def funA(desA):
print("It's funA")
print('---')
print(desA)
desA()
print('---')
def funB(desB):
print("It's funB")
@funB
@funA
def funC():
print("It's funC")
运行结果:
It's funA
---
<function funC at 0x00000252D2545550>
It's funC
---
It's funB
解析:
- @funB 修饰装饰器@funA,@funA 修饰函数定义def funC(),将funC()作为funA()的参数,再将funA(funC())作为funB()的参数。 执行的时候自下而上,先执行funA(funC()),再执行funB(funA(funC()))。
注意,funC()并不执行,除非funA()函数中给出了执行funA()的代码。 - 打印desA,其传的是funC()的地址,即desA现在为函数desA()。 执行desA()即执行funC(),
desA=desA()=funC()。
调用被修饰函数时,自动执行添加的功能代码
这块内容参考自:装饰器 - 廖雪峰的官方网站
def now():
print('2015-3-25')
def log(func):
print('Jason')
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
@log
def now():
print('2015-3-25')
执行上面后输出如下:
Jason
调用now()函数时,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:
>>> now()
call now():
2015-3-25
由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。
wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。
如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本:
def now():
print('2015-3-25')
def log(text):
print('Jason')
def decorator(func):
print('Cool')
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log('execute')
def now():
print('2015-3-25')
执行上面后输出如下:
Jason
Cool
调用now()函数时:
>>> now()
execute now():
2015-3-25
我们来剖析上面的语句,首先执行log('execute'),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数。
@property
Python内置的@property
就是很常用的一个装饰器,负责把一个方法变成属性调用。
class DataSet(object):
def __init__(self):
self._images = 1
self._labels = 2 #定义属性的名称
@property
def images(self): #方法加入@property后,这个方法相当于一个属性,这个属性可以让用户进行使用,而且用户有没办法随意修改。
return self._images
@property
def labels(self):
return self._labels
l = DataSet()
#用户进行属性调用的时候,直接调用images即可,而不用知道属性名_images,因此用户无法更改属性,从而保护了类的属性。
print(l.images) # 加了@property后,可以用调用属性的形式来调用方法,后面不需要加()。
二、表示矩阵乘法。
不常用。是torch.matmul()的重写
例:
import torch
n=100
x = torch.ones(n,2)
x[:,0].uniform_(-1.,1) # 第一列变换至(-1.,1) 之间
print(x[:5]) # 输出前5行
a = torch.tensor([3.,2.]) # 一维Tensor
print(a)
print(a.shape)
y = x@a
print(y)
print(y.shape)
输出结果:
tensor([[ 0.8230, 1.0000],
[ 0.2427, 1.0000],
[-0.7416, 1.0000],
[-0.1267, 1.0000],
[ 0.7767, 1.0000]])
tensor([3., 2.])
torch.Size([2])
tensor([ 4.4691, 2.7281, -0.2249, 1.6198, 4.3302, 3.3386, 1.9908, -0.8602,
4.9401, 1.9773, 4.5304, -0.1322, 3.9059, -0.6714, 1.8961, 3.7886,
0.8241, 4.4958, 2.2765, 2.0459, 3.6542, 3.0824, 2.8941, 1.0526,
4.8735, 1.4954, 3.0208, 4.0778, 2.3491, 2.2261, 3.1072, 1.0640,
1.7861, -0.8534, 3.2532, 1.5553, 0.2124, 3.6449, 1.6078, -0.1138,
4.2842, 3.7184, 2.2547, 3.4069, 3.6274, 0.4879, 1.4638, 3.9289,
3.3475, 4.1895, 1.5572, 0.8312, 2.9297, -0.9266, 0.4067, 2.5237,
0.6808, 4.9553, 3.3838, 0.5514, 4.8429, 0.0513, 3.4206, 0.3634,
4.7817, 3.0385, 2.3276, -0.0794, 3.4981, 4.3776, -0.8681, -0.4573,
3.6906, 1.2463, 1.4817, 4.0007, 4.7871, 2.5638, 4.2755, 3.1731,
3.4726, 2.1015, -0.8896, 1.4156, 1.2603, 4.0047, 3.3631, 3.5998,
3.2414, -0.1534, 3.6266, 0.3750, 4.4118, -0.0199, 1.6172, 3.2992,
-0.2325, 1.8240, 0.5580, 2.1420])
torch.Size([100])