Синтаксически нет.Однако это сделать относительно просто, используя декоратор:
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
Используется как:
>>> @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
Декоратор игнорирует позиционные и ключевые аргументы, не включенные в данный список:
>>> @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
Если аргументы могут быть «необязательными» (т. Е. Вы можете указать не более одного из этих ключевых аргументов, но можете также опустить все из них), просто измените != 1
на <= 1
или in (0,1)
, как выпредпочитайте.
Если вы замените 1
на число k
, вы обобщите декоратор для точного (или не более) k
указанного аргумента из предоставленного вами набора.
Это, однако, не поможет PyCharm в любом случае.Насколько я знаю, в настоящее время просто невозможно сказать IDE, что вы хотите.
В вышеприведенном декораторе есть небольшая "ошибка": он считает foo=None
как если бы вы передали значение для foo
так как он появляется в списке kwargs
.Обычно вы ожидаете, что передача значения по умолчанию должна вести себя идентично, как если бы вы вообще не указывали аргумент.
Чтобы исправить это правильно, потребуется проверить func
внутри wrapper
, чтобы найти значения по умолчанию и изменитьk in keywords
с чем-то вроде k in keywords and kwargs[k] != defaults[k]
.