Какова лучшая практика для обработки кортежей единственной стоимости в Пайтоне?

Я использую стороннюю функцию библиотеки, которая читает ряд ключевых слов из файла и, как предполагается, возвращает кортеж из ценностей. Это делает это правильно, пока есть по крайней мере два ключевых слова. Однако в случае, где есть только одно ключевое слово, оно возвращает сырую последовательность, не кортеж размера один. Это особенно пагубно потому что, когда я пытаюсь сделать что-то как

for keyword in library.get_keywords():
    # Do something with keyword

, в случае единственного ключевого слова, for повторяет по каждому характеру последовательности по очереди, которая не бросает исключения, во времени выполнения или иначе, но тем не менее абсолютно бесполезна мне.

Мой вопрос двойной:

Очевидно это - ошибка в библиотеке, которая находится вне моего контроля. Как я могу лучше всего работать вокруг этого?

Во-вторых, в целом, если я пишу функцию, которая возвращает кортеж, какова лучшая практика для обеспечения кортежей с одним элементом, правильно произведены? Например, если я имею

def tuple_maker(values):
    my_tuple = (values)
    return my_tuple

for val in tuple_maker("a string"):
    print "Value was", val

for val in tuple_maker(["str1", "str2", "str3"]):
    print "Value was", val

Я добираюсь

Value was a
Value was  
Value was s
Value was t
Value was r
Value was i
Value was n
Value was g
Value was str1
Value was str2
Value was str3

Что лучший способ состоит в том, чтобы изменить функцию my_tuple на самом деле возвратить кортеж, когда есть только единственный элемент? Сделайте я явно должен проверить, равняется ли размер 1, и создайте кортеж отдельно, используя (value,) синтаксис? Это подразумевает, что любая функция, у которой есть возможность возвращения однозначного кортежа, должна сделать это, которое кажется hacky и повторяющийся.

Есть ли некоторое изящное общее решение этой проблемы?

13
задан ire_and_curses 21 January 2010 в 18:22
поделиться

7 ответов

Вам необходимо как-то тестировать на тип, если это строка или кортеж. Я бы сделал это так:

keywords = library.get_keywords()
if not isinstance(keywords, tuple):
    keywords = (keywords,) # Note the comma
for keyword in keywords:
    do_your_thang(keyword)
17
ответ дан 1 December 2019 в 19:50
поделиться

Для вашей первой проблемы я не совсем уверен, что это лучший ответ, но я думаю, что вам нужно проверить, является ли возвращенное значение строкой или кортежным и действовать соответственно.

Что касается вашей второй проблемы, любая переменная может быть превращена в единый ценный кортеж, размещая , рядом с ним:

>>> x='abc'
>>> x
'abc'
>>> tpl=x,
>>> tpl
('abc',)

Сделать эти две идеи вместе:

>>> def make_tuple(k):
...     if isinstance(k,tuple):
...             return k
...     else:
...             return k,
... 
>>> make_tuple('xyz')
('xyz',)
>>> make_tuple(('abc','xyz'))
('abc', 'xyz')

Примечание: ИМХО Как правило, плохая идея использовать Isinstance или любую другую форму логики, которая должна проверять тип объекта во время выполнения. Но для этой проблемы я не вижу вокруг этого.

8
ответ дан 1 December 2019 в 19:50
поделиться

Всегда есть обезьяна!

# Store a reference to the real library function
really_get_keywords = library.get_keywords

# Define out patched version of the function, which uses the real
# version above, adjusting its return value as necessary
def patched_get_keywords():
    """Make sure we always get a tuple of keywords."""
    result = really_get_keywords()
    return result if isinstance(result, tuple) else (result,)

# Install the patched version
library.get_keywords = patched_get_keywords

Примечание: Этот код может сжигать свой дом и спать с вашей женой.

2
ответ дан 1 December 2019 в 19:50
поделиться

, а не проверка на протяжении 1, я бы использовал встроенный Isinstance.

>>> isinstance('a_str', tuple)
False
>>> isinstance(('str1', 'str2', 'str3'), tuple)
True
1
ответ дан 1 December 2019 в 19:50
поделиться
3796789-

Это абсолютно необходимо, чтобы он возвращал кортежи, или будет любые сведения?

import collections
def iterate(keywords):
    if not isinstance(keywords, collections.Iterable):
        yield keywords
    else:
        for keyword in keywords:
            yield keyword


for keyword in iterate(library.get_keywords()):
    print keyword
1
ответ дан 1 December 2019 в 19:50
поделиться

для первой проблемы вы можете проверить, не является ли возвращаемое значение кортежом, используя

type(r) is tuple
#alternative
isinstance(r, tuple)
# one-liner
def as_tuple(r): return [ tuple([r]), r ][type(r) is tuple]

, вторую вещь, которую я люблю использовать tuple([1]). подумайте, что это дело вкуса. возможно, также можно было бы написать обертку, например def tuple1(s): return tuple([s])

0
ответ дан 1 December 2019 в 19:50
поделиться

Ваш TUPLE_MAKER не делает то, что вы думаете, что это делает. Эквивалентное определение Maker Tupple к вашему

def tuple_maker(input):
    return input

, что вы видите, состоит в том, что TUPLE_MAKER («a String») возвращает строку, а TUPLE_MAKER ([» str1 "," Str2 "," Str3 "]) Возвращает список строк; Ни вернуть кортеж!

Форты в Python определяются наличием запятых, а не скобок. Таким образом, (1,2) представляет собой кортеж, содержащий значения 1 и 2 , а (1,) - кортеж, содержащий одно значение 1 .

Чтобы преобразовать значение в кортеж, поскольку другие указали, используйте кортеж .

>>> tuple([1])
(1,)
>>> tuple([1,2])
(1,2)
3
ответ дан 1 December 2019 в 19:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: