Помните, что в Python мы хотим использовать «Duck Typing». Таким образом, все, что действует как список, может рассматриваться как список. Поэтому не проверяйте тип списка, просто посмотрите, действует ли он как список.
Но строки тоже действуют как список, и часто это не то, что мы хотим. Есть моменты, когда это даже проблема! Так что, проверяйте явно строку, но затем используйте утку.
Вот функция, которую я написал для удовольствия. Это специальная версия, 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()
делает эта проверка? Это что-то вроде хака. Но это важно.
Эта функция вызывает себя рекурсивно для всего, что действует как список. Если бы мы не обрабатывали строку специально, то она была бы обработана как список и разделена по одному символу за раз. Но тогда рекурсивный вызов попытается обработать каждый символ как список - и это сработает! Даже односимвольная строка работает как список! Функция будет продолжать вызывать себя рекурсивно, пока стек не переполнится.
Подобные функции, которые зависят от каждого рекурсивного вызова, разбивающего выполняемую работу, должны иметь строки специального случая - потому что вы не можете разбить строку ниже уровня односимвольной строки, и даже одну Строка -character действует как список.
Примечание: 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__()
я изменил выше.