Моя функция получает объект myenum
, который может быть set
или dict
.{'a', 'b', 'c'}
или{'a': 5, 'b' : 2, 'c' : 8}
Он представляет перечисление, как в C/C++.
В случае dict
мне нужно перечислить .items()
в случае set
мне нужно использовать enumerate(myenum)
вот так
for k, i in myenum.items():
for i, k in enumerate(myenum):
Я мог бы использовать тройную систему itr = myenum.items() if hasattr(myenum, 'keys') else enumerate(myenum)
А потом просто иметь сингл for
.
К сожалению, .items()
расширяется до key, value
, а enumerate()
расширяется до index, key
. index
на самом деле является желаемым значением перечисления.
Есть ли возможность поменяться местами в дополнении? Значит, enumerate()
тоже превращается в key, index
?
Прямо сейчас у меня есть наивное решение из двух одинаковых циклов for
, только порядок k, i
разный, что некрасиво.
Используете ли вы значения в цикле for в случае dict? Было бы полезно, если бы вы показали больше кода в циклах.
Это тот случай, когда вызывающая сторона, а не ваша функция, должна нести ответственность за создание соответствующего значения Iterable[str, int]
из любого имеющегося у них набора, словаря и т. д.
@matszwecja Python — это язык утиного набора текста, существует бесконечное количество тем, доказывающих, что использование isinstance
— худший подход. Если объект является итеративным и имеет ключи - для меня это так, даже если он не является производным от dict. Завтра эта функция тоже получит dict
и ваш код сломается, а мой все еще будет в порядке
Вы можете заархивировать set
с помощью range
и преобразовать его в dict
.
def func(myenum):
if isinstance(myenum, set):
myenum = dict(zip(myenum, range(len(myenum))))
for k, i in myenum.items():
print(k, i)
Должен признать, это элегантная альтернатива моей проблеме и она мне нравится. К сожалению, другой ответ от fsimonjetz больше соответствует теме вопроса, поэтому пришлось принять его. Тем не менее, большое спасибо! Однако одно замечание. Поскольку Python использует утиный ввод, проверка на isinstance
менее выгодна. Но это незначительно
Есть ли возможность поменяться местами в дополнении? Итак, enumerate() также расширяется до ключа и индекса?
Если вам нужно только поменять их местами, это должно вести себя точно так же, как enumerate
, за исключением замененных элементов.
def swap_enumerate(enum):
return ((k, i) for i, k in enumerate(enum))
Хотя мне больше нравится решение @Guy, но оно отвечает именно на мой вопрос, поэтому я принимаю его. Спасибо!
Я бы исправил set
в dict
, если это применимо. Тогда я бы имел дело только с dict
.
def f( myenum ):
if isinstance(myenum, set):
myenum = { v : k for k, v in enumerate(myenum) }
for key, value in myenum.items():
...
Разложите свою функцию на две более простые функции: одна преобразует набор или словарь в соответствующую итерацию, а другая использует итерацию.
from typing import Iterable, TypeVar
K = TypeVar('K')
def convert(c: dict[K, int] | set[K]) -> Iterable[tuple[K, int]]:
if isinstance(c, dict):
return c.items()
else:
return ((k, i) for i, k in enumerate(c))
def process(pairs: Iterable[K, int]):
for k, i in pairs:
...
def func(c: dict[K, int] | set[K]):
process(convert(c))
Вы можете рассмотреть возможность реализации только process
и оставить convert
для реализации тому, кто хочет использовать process
.
Не проверяйте, принадлежит ли объект заданному типу с помощью
hasattr
, вместо этого используйтеisinstance
.