Как проверить, является ли объект списком или кортежем (но не строкой)?

Добавляя к вышесказанному, я также видел, что большая часть времени help () действительно помогает

. Например, он дает всю информацию о необходимых аргументах.

help(<method>)

дает ниже

method(self, **kwargs) method of apiclient.discovery.Resource instance
Retrieves a report which is a collection of properties / statistics for a specific customer.

Args:
  date: string, Represents the date in yyyy-mm-dd format for which the data is to be fetched. (required)
  pageToken: string, Token to specify next page.
  parameters: string, Represents the application name, parameter name pairs to fetch in csv as app_name1:param_name1, app_name2:param_name2.

Returns:
  An object of the form:

    { # JSON template for a collection of usage reports.
    "nextPageToken": "A String", # Token for retrieving the next page
    "kind": "admin#reports#usageReports", # Th
414
задан kenorb 30 April 2017 в 20:02
поделиться

5 ответов

Только в python 2 (не в python 3):

assert not isinstance(lst, basestring)

Это на самом деле то, что вам нужно, иначе вы упустите много вещей, которые действуют как списки, но не являются подклассами из списка или кортежа .

326
ответ дан 22 November 2019 в 23:20
поделиться

Я обычно делаю это (если действительно, действительно должен был):

for i in some_var:
   if type(i) == type(list()):
       #do something with a list
   elif type(i) == type(tuple()):
       #do something with a tuple
   elif type(i) == type(str()):
       #here's your string
-6
ответ дан 22 November 2019 в 23:20
поделиться

Объект str не имеет атрибута __ iter __

>>> hasattr('', '__iter__')
False 

, поэтому вы можете выполнить проверку

assert hasattr(x, '__iter__')

, и это также вызовет nice AssertionError и для любого другого не повторяемого объекта.

Изменить: Как Тим упоминает в комментариях, это будет работать только в python 2.x, но не в 3.x

5
ответ дан 22 November 2019 в 23:20
поделиться

Вообще говоря, тот факт, что функция, которая выполняет итерацию по объекту, работает со строками, а также с кортежами и списками, является скорее особенностью, чем ошибкой. Вы, конечно, можете использовать isinstance или утиный ввод, чтобы проверить аргумент, но почему вы должны?

Это звучит как риторический вопрос, но это не так. Ответ на вопрос «зачем мне проверять тип аргумента?» вероятно предложит решение реальной проблемы, а не предполагаемой проблемы. Почему это ошибка, когда в функцию передается строка? Также: если это ошибка, когда строка передается в эту функцию, является ли это также ошибкой, если ей передается какой-либо другой итерабель, не являющийся списком / кортежем? Почему или почему нет?

Я думаю, что наиболее частым ответом на этот вопрос будет тот, что разработчики пишут f ("abc" ) ожидают, что функция будет вести себя так, как если бы они написали f (["abc"]) . Вероятно, существуют обстоятельства, когда имеет больше смысла защищать разработчиков от самих себя, чем поддерживать вариант использования итерации по символам в строке. Но сначала я бы хорошенько об этом подумал.

10
ответ дан 22 November 2019 в 23:20
поделиться

Помните, что в Python мы хотим использовать «утиную печать». Итак, все, что действует как список, можно рассматривать как список. Итак, не проверяйте тип списка, просто посмотрите, действует ли он как список.

Но строки также действуют как список, и часто это не то, что нам нужно. Бывают случаи, когда это даже проблема! Итак, проверьте явно наличие строки, но затем используйте утиную печать.

Вот функция, которую я написал для развлечения. Это специальная версия repr () , которая выводит любую последовательность в угловых скобках ('<', '>').

def srepr(arg):
    if isinstance(arg, basestring): # Python 3: isinstance(arg, str)
        return repr(arg)
    try:
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    except TypeError: # catch when for loop fails
        return repr(arg) # not a sequence so just return repr

В целом это чисто и элегантно. Но что там делает эта проверка isinstance () ? Это своего рода взлом. Но это важно.

Эта функция рекурсивно вызывает себя для всего, что действует как список. Если бы мы специально не обрабатывали строку, тогда он будет рассматриваться как список и разбивать по одному символу за раз. Но тогда рекурсивный вызов будет пытаться рассматривать каждый символ как список - и это сработает! Даже односимвольная строка работает как список! Функция будет продолжать вызывать себя рекурсивно до переполнения стека.

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

Примечание: try / except - самый чистый способ выразить наши намерения. Но если бы этот код был критичным по времени, мы могли бы заменить его каким-то тестом, чтобы проверить, является ли arg последовательностью. Вместо того, чтобы проверять тип, мы, вероятно, должны проверить поведение. Если у него есть метод .strip () , это строка, поэтому не считайте ее последовательностью; в противном случае, если он индексируемый или повторяемый, это последовательность:

def is_sequence(arg):
    return (not hasattr(arg, "strip") and
            hasattr(arg, "__getitem__") or
            hasattr(arg, "__iter__"))

def srepr(arg):
    if is_sequence(arg):
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    return repr(arg)

РЕДАКТИРОВАТЬ: Я изначально написал выше с проверкой на __ getslice __ () , но я заметил, что в модуле collections документации, интересным методом является __ getitem __ () ; это имеет смысл, вот как вы индексируете объект. Это кажется более фундаментальным, чем __ getslice __ () , поэтому я изменил приведенное выше.

Первоначально я писал выше с проверкой на __ getslice __ () , но я заметил, что в документации модуля collections интересным методом является __ getitem __ () ; это имеет смысл, вот как вы индексируете объект. Это кажется более фундаментальным, чем __ getslice __ () , поэтому я изменил приведенное выше.

Первоначально я писал выше с проверкой на __ getslice __ () , но я заметил, что в документации модуля collections интересным методом является __ getitem __ () ; это имеет смысл, вот как вы индексируете объект. Это кажется более фундаментальным, чем __ getslice __ () , поэтому я изменил приведенное выше.

170
ответ дан 22 November 2019 в 23:20
поделиться
Другие вопросы по тегам:

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