参数个数可变
为什么我们会使用*args和**kwargs表示输入的参数呢?因为当参数个数不确定的时候,不能够使用基于位置的参数表示方式,我们会使用(*args, **kwargs)来自动适应变参数和命名参数。这意味着,我们想往函数中输入多少个参数都行,分别以元组形式,字典形式传递参数。
def test(*args,**kwargs):
print(type(args),args)
print(type(kwargs),kwargs)
test("test",y='test2')
<class 'tuple'> ('test',)
<class 'dict'> {'y': 'test2'}
从上面的例子可以看出,args负责位置参数,并且将参数放到了元组tuple中。而kwargs(key word arguments)负责关键字参数,将参数放到了字典(dict)中。
名称不唯一
*args和 **kwargs变量前面的*是必须的。args和kwargs名称是一个常用的书写方式。换成*v和**vs或者别的都可以。
其中**kwargs传入的参数必须形式上有key-value才行。例如
a=(1,2,3)
b=[1,2,3]
c={1,2,3}
d={1:1,2:2,3:3}
test(a)
<class 'tuple'> ((1, 2, 3),)
<class 'dict'> {}
test(b)
<class 'tuple'> ([1, 2, 3],)
<class 'dict'> {}
test(c)
<class 'tuple'> ({1, 2, 3},)
<class 'dict'> {}
test(d)
<class 'tuple'> ({1: 1, 2: 2, 3: 3},)
<class 'dict'> {}
test(a,b,c,d)
<class 'tuple'> ((1, 2, 3), [1, 2, 3], {1, 2, 3}, {1: 1, 2: 2, 3: 3})
<class 'dict'> {}
test(a,y=b,z=c)
<class 'tuple'> ((1, 2, 3),)
<class 'dict'> {'y': [1, 2, 3], 'z': {1, 2, 3}}
此外,*和** 有解包的功能
*和**还可用于列表、元组、字典的解包,但是*后的参数必须是一个迭代器。例如
In [7]: a=(1,2,3)
In [8]: print(a)
(1, 2, 3)
In [9]: print(*a)
1 2 3
In [10]: b={'1':'name', '2':'age'}
In [11]: print(*b)
1 2
使用
例如,当使用*args接受参数的时候,会遇到判断,并对输入参数进行处理。下面是一个处理的例子。
from collections import OrderedDict
#**省略**
def __init__(self, *args):
super(Sequential, self).__init__()
if len(args) == 1 and isinstance(args[0], OrderedDict):
for key, module in args[0].items():
self.add_module(key, module)
else:
for idx, module in enumerate(args):
self.add_module(str(idx), module)
#**省略**
# Example of using Sequential with OrderedDict
model = nn.Sequential(OrderedDict([
('conv1', nn.Conv2d(1,20,5)),
('relu1', nn.ReLU()),
('conv2', nn.Conv2d(20,64,5)),
('relu2', nn.ReLU())
]))
补充
isinstance()
isinstance() 函数来判断一个对象是否是一个已知的类型。与type对比:isinstance()会认为子类是父类类型,考虑继承关系。type()不会认为子类是一种父类类型,不考虑继承关系。
class A:
pass
class B(A):
pass
isinstance(A(), A) # returns True
type(A()) == A # returns True
isinstance(B(), A) # returns True
isinstance(B,A) # returns False
type(B()) == A # returns False
OrderedDict
字典的子类OrderedDict,保存了被添加的顺序。
官网OrderedDict
常规的 dict 被设计为非常擅长映射操作。 跟踪插入顺序是次要的。OrderedDict 旨在擅长重新排序操作。 空间效率、迭代速度和更新操作的性能是次要的。
算法上, OrderedDict 可以比 dict 更好地处理频繁的重新排序操作。 这使其适用于跟踪最近的访问(例如在 LRU cache 中)。
对于 OrderedDict ,相等操作检查匹配顺序。
OrderedDict 类的 popitem() 方法有不同的签名。它接受一个可选参数来指定弹出哪个元素。
OrderedDict 类有一个 move_to_end() 方法,可以有效地将元素移动到任一端。