Пам’ятайте, що в 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()
там чекає? Це свого роду хак. Але це істотно.
Ця функція рекурсивно викликає все, що діє як список. Якщо ми не обробляли рядок спеціально, то вона буде розглядатися як список і розділяти по одному символу за один раз. Але тоді рекурсивний виклик спробував би розглянути кожного символу як список - і він би спрацював! Навіть односимвольна рядок працює як список! Функція продовжувала б викликати себе рекурсивно, поки стек не переповнюється.
Функції, такі як ця, що залежать від кожного рекурсивного виклику, що розбиває роботу, яку потрібно виконати, повинні мати рядки спеціального регістру - тому що ви не можете розбити рядок нижче рівня односимвольної струни та навіть однієї -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)
EDIT: Спочатку я писав вище з чеком, __getslice__()
але помітив, що в collections
документації на модуль цікавий метод __getitem__()
; це має сенс, саме так ви індексуєте об’єкт. Це здається більш принциповим, ніж __getslice__()
я змінив вище.