[toc]

前言:在做GAN的时候,发现人家的代码都是用fire来控制输入的,觉得很实用,方便把一个大工程控制参数,因此来学习下

〇.遇到的小问题!!!

shell命令的时候,函数后面需要空一格再打要传入的参数!

1
2
>python first.py test --name=QIN --age=21
name is QIN,age is 21 and address is ('sc', 'cd').

Ⅰ.全部暴露

什么都不做,只是在调用的时候fire.Fire(),会把所有程序暴露给命令行(我猜这个暴露的意思类似于是否private)

1
2
3
4
5
6
7
8
import fire
def hello(name):
return('Hello {name} !'.format(name=name))
if __name__ == "__main__":
fire.Fire()

python first.py hello QIN#hello 是为了指定hello函数
Hello QIN !

Ⅱ.只将某个函数暴露

fire.Fire(<fn>),同时因为已经指定了就是运行这个函数,所以命令行里不用打hello了

1
2
3
4
5
6
7
8
import fire
def hello(name):
return('Hello {name} !'.format(name=name))
if __name__ == "__main__":
fire.Fire(hello)

python first.py ZHENG
Hello ZHENG !

Ⅲ.暴露多个函数

1.直接暴露

原理也一样的,其实整个代码中的所有函数都暴露了。

1
2
3
4
5
6
7
8
9
10
11
import fire
def add(x, y):
return x + y
def multiply(x, y):
return x * y
if __name__ == '__main__':
fire.Fire()
python example.py add 10 20
30
python example.py multiply 10 20
200

你会注意到Fire正确地将1020解析为数字,而不是字符串。 可以看0X09 参数解析

2.暴露多个函数(字典)

通过字典来实现,使用方法还是和原来一样,不过可以更换函数名字来使用了

1
2
3
4
5
6
7
8
9
10
import fire
def add(x, y):
return x + y
def multiply(x, y):
return x * y
if __name__ == '__main__':
fire.Fire({
'fun1': add,
'fun2': multiply,
})

暴露对象(object)中的多个函数

这是暴露多个命令的一个好的做法。其实相当于打了个包

1
2
3
4
5
6
7
8
9
10
import fire
class Calculator(object):
def add(self, x, y):
return x + y
def multiply(self, x, y):
return x * y

if __name__ == '__main__':
calculator = Calculator()
fire.Fire(calculator)

暴露类(class)中的多个函数

Fire也适用于class。 这是暴露多个命令的另一个好的做法。

1
2
3
4
5
6
7
8
9
10
11
import fire
class Calculator(object):
def add(self, x, y):
return x + y
def multiply(self, x, y):
return x * y

if __name__ == '__main__':
fire.Fire(Calculator)
python example.py multiply 10 20
200

为什么要用类呢,因为这样你可以给构造类传递参数__init_函数的参数必须用--flag语法传递:

1
2
3
4
5
6
7
8
9
10
11
import fire
class test(object):
def __init__(slelf,name=''):#加这个主要是为了如果没有输入的情况下给个默认值
slelf.name=name
def pr(self):
print('name is '+self.name)

if __name__ == '__main__':
fire.Fire(test)
>python first.py pr --name=QIN
>name is QIN

因为在主函数里面还没有实例化,因此相当于可以自己改变类的参数。

Ⅳ.带*args和**kwargs的函数

同一个类内

1
2
3
4
5
6
7
8
9
import fire
def test(*args):
sort=sorted(args,key=lambda num: num)#这个写法挺有趣
# print(args)
return(sort)
if __name__ == '__main__':
fire.Fire(test)
>python first.py 456 12 450 57 8 55
>8 12 55 57 450 456

你可以使用分隔符给函数提供参数。分隔符后的所有参数将用于处理函数的结果,而不是传递给函数本身。 默认分隔符是连字符-

以下是我们使用分隔符的示例。

1
2
3
$ python example.py dog cat elephant - upper
CAT DOG ELEPHANT
12

如果没有分隔符,upper就会被当作另一个参数。

1
2
$ python example.py dog cat elephant upper
cat dog upper elephant

不同类内(GAN代码所用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import fire
class Config(object):
name='NULL'
age=0
add=('sc','cd')
opt=Config()

def test(**kwargs):
for k_, v_ in kwargs.items():#这个写法非常重要!!!
# print(k_,v_)
setattr(opt, k_, v_)
print('name is {},age is {} and address is {}.'.format(opt.name,opt.age,str(opt.add)))
if __name__ == "__main__" :
fire.Fire()

>python first.py test --name=QIN --age=21
>name is QIN,age is 21 and address is ('sc', 'cd').

参数解析

参数的类型取决于它们的值,而不是使用它们的函数签名。 您可以从命令行传递任何Python文本:数字,字符串,元组,列表,字典(仅在某些版本的Python中支持集合)。只要它们只包含文字,您也可以任意嵌套这些集合。

为了演示这个,我们将制作一个小程序,通过这个小程序告诉我们传给它的参数类型:

1
2
3
import fire
fire.Fire(lambda obj: type(obj).__name__)
12

我们会像这样使用它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ python example.py 10
int
$ python example.py 10.0
float
$ python example.py hello
str
$ python example.py '(1,2)'
tuple
$ python example.py [1,2]
list
$ python example.py True
bool
$ python example.py {name: David}
dict
1234567891011121314

在最后一个例子中,你会注意到裸词会自动替换为字符串。

要注意! 如果你想传递字符串"10"而不是int 10,你需要转义或者引用你的引号。 否则,Bash将会把你的引用取消并将一个没有引号的10传递给你的Python程序,在那里Fire将把它解释为一个数字。

1
2
3
4
5
6
7
8
9
10
11
$ python example.py 10
int
$ python example.py "10"
int
$ python example.py '"10"'
str
$ python example.py "'10'"
str
$ python example.py \"10\"
str
12345678910

要注意! 记住Bash首先处理你的参数,然后Fire解析结果。 如果你想将dict {"name":"David Bieber"}传递给你的程序,你可以试试这个:

1
2
3
4
5
6
7
8
9
10
11
$ python example.py '{"name": "David Bieber"}'  # Good! Do this.
dict
$ python example.py {"name":'"David Bieber"'} # Okay.
dict
$ python example.py {"name":"David Bieber"} # Wrong. This is parsed as a string.
str
$ python example.py {"name": "David Bieber"} # Wrong. This isn't even treated as a single argument.
<error>
$ python example.py '{"name": "Justin Bieber"}' # Wrong. This is not the Bieber you're looking for. (The syntax is fine though :))
dict
12345678910

bool类型参数

TrueFalse被解析为布尔值。

你也可以通过--flag语法--name--noname来指定布尔值,它们分别将名称设置为TrueFalse

继续前面的例子,我们可以运行以下任何一个:

1
2
3
4
5
6
7
8
9
$ python example.py --obj=True
bool
$ python example.py --obj=False
bool
$ python example.py --obj
bool
$ python example.py --noobj
bool
12345678

要注意! 如果除另一个标志之外的标志紧跟在应该是布尔值的标志之后,该标志将取代该标志的值而不是布尔值。 您可以解决这个问题:通过在最后一个标志之后放置一个分隔符,明确指出布尔标志的值(如--obj = True),或者确保在布尔标志参数后面有另一个标志。