Sam*_*son 2 python optional-parameters optional-arguments keyword-argument python-3.x
考虑:
def foobar(*, foo, bar):
if foo:
print('foo', end="")
if bar:
print('bar', end="")
if foo and bar:
print('No bueno', end='') # I want this to be impossible
if not foo and not bar:
print('No bueno', end='') # I want this to be impossible
print('')
foobar(foo='bar') # I want to pass inspection
foobar(bar='foo') # I want to pass inspection
foobar(foo='bar', bar='foo') # I want to fail inspection
foobar() # I want to fail inspection
Run Code Online (Sandbox Code Playgroud)
有没有一种方法可以设置一个函数,使调用它的方法仅在仅传递foo或bar时才通过检查,而无需手动检查函数内部?
语法上不可以。但是,使用装饰器执行此操作相对容易:
from functools import wraps
def mutually_exclusive(keyword, *keywords):
keywords = (keyword,)+keywords
def wrapper(func):
@wraps(func)
def inner(*args, **kwargs):
if sum(k in keywords for k in kwargs) != 1:
raise TypeError('You must specify exactly one of {}'.format(', '.join(keywords)))
return func(*args, **kwargs)
return inner
return wrapper
Run Code Online (Sandbox Code Playgroud)
用作:
>>> @mutually_exclusive('foo', 'bar')
... def foobar(*, foo=None, bar=None):
... print(foo, bar)
...
>>> foobar(foo=1)
1 None
>>> foobar(bar=1)
None 1
>>> foobar(bar=1, foo=2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in inner
TypeError: You must specify exactly one of foo, bar
>>> foobar()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in inner
TypeError: You must specify exactly one of foo, bar
Run Code Online (Sandbox Code Playgroud)
装饰器忽略给定列表中未包括的位置和关键字参数:
>>> @mutually_exclusive('foo', 'bar')
... def foobar(a,b,c, *, foo=None, bar=None, taz=None):
... print(a,b,c,foo,bar,taz)
...
>>> foobar(1,2,3, foo=4, taz=5)
1 2 3 4 None 5
>>> foobar(1,2,3, foo=4, bar=5,taz=6)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in inner
TypeError: You must specify exactly one of foo, bar
Run Code Online (Sandbox Code Playgroud)
如果参数可能是“可选的”(即,您最多可以指定这些关键字参数之一,但也可以省略所有这些参数),则只需更改!= 1为<= 1或in (0,1)根据需要即可。
如果1用数字替换,k则装饰器将泛化为k从提供的集合中准确(或最多)接受指定的参数。
但是,这无论如何都不会帮助PyCharm。据我所知,目前完全不可能告诉IDE您想要什么。
上面的装饰器有一个小“ bug”:由于它出现在列表中,因此认为foo=None您传递了一个值。通常,您希望传递默认值的行为与完全没有指定参数的行为相同。fookwargs
正确修复,这将需要检查func里面wrapper查找默认值和变化k in keywords的东西像k in keywords and kwargs[k] != defaults[k]。