Как определить, является ли переменная python строкой или списком?
У меня есть подпрограмма, которая берет список строк в качестве параметра, но я хочу поддерживать передачу в одной строке и преобразовывать ее в список одной строки. Например:
def func( files ):
for f in files:
doSomethingWithFile( f )
func( ['file1','file2','file3'] )
func( 'file1' ) # should be treated like ['file1']
Как моя функция может определить, была ли передана строка или список? Я знаю, что есть функция type
, но есть ли "более питонический" способ?
Ответы
Ответ 1
Ну, нет ничего лишнего в том, чтобы проверять тип. Сказав это, если вы готовы наложить небольшую нагрузку на вызывающего абонента:
def func( *files ):
for f in files:
doSomethingWithFile( f )
func( *['file1','file2','file3'] ) #Is treated like func('file1','file2','file3')
func( 'file1' )
Я бы сказал, что это более pythonic в том, что "явный лучше, чем неявный". Здесь есть хотя бы признание со стороны вызывающего абонента, когда вход уже находится в форме списка.
Ответ 2
isinstance(your_var, basestring)
Ответ 3
Лично мне не нравится такое поведение - это мешает печатать на утке. Можно утверждать, что он не подчиняется "Явной лучше, чем неявной" мантре. Почему бы не использовать синтаксис varargs:
def func( *files ):
for f in files:
doSomethingWithFile( f )
func( 'file1', 'file2', 'file3' )
func( 'file1' )
func( *listOfFiles )
Ответ 4
Я бы сказал, что большинство способов Python'а состоит в том, чтобы заставить пользователя всегда передавать список, даже если в нем есть только один элемент. Это делает его действительно очевидным. func()
может взять список файлов
def func(files):
for cur_file in files:
blah(cur_file)
func(['file1'])
Как предложил Дейв, вы можете использовать синтаксис func(*files)
, но мне никогда не нравилась эта функция, и она кажется более явной ( "явный лучше, чем неявный" ), чтобы просто потребовать список. Он также превращает ваш специальный случай (вызов func
с одним файлом) в случай по умолчанию, потому что теперь вам нужно использовать дополнительный синтаксис для вызова func
со списком.
Если вы хотите сделать особый случай для аргумента, являющегося строкой, используйте isinstance()
builtin и сравните с basestring
(из которых как str()
, так и unicode()
):
def func(files):
if isinstance(files, basestring):
doSomethingWithASingleFile(files)
else:
for f in files:
doSomethingWithFile(f)
Действительно, я предлагаю просто потребовать список, даже с одним файлом (в конце концов, он требует только двух дополнительных символов!)
Ответ 5
if hasattr(f, 'lower'): print "I'm string like"
Ответ 6
def func(files):
for f in files if not isinstance(files, basestring) else [files]:
doSomethingWithFile(f)
func(['file1', 'file2', 'file3'])
func('file1')
Ответ 7
Если у вас больше контроля над вызывающим, тогда один из других ответов лучше. У меня нет такой роскоши в моем случае, поэтому я остановился на следующем решении (с оговорками):
def islistlike(v):
"""Return True if v is a non-string sequence and is iterable. Note that
not all objects with getitem() have the iterable attribute"""
if hasattr(v, '__iter__') and not isinstance(v, basestring):
return True
else:
#This will happen for most atomic types like numbers and strings
return False
Этот подход будет работать для случаев, когда вы имеете дело с набором знаний типов, подобных спискам, которые соответствуют вышеуказанным критериям. Однако некоторые типы последовательностей будут пропущены.
Ответ 8
Varargs запутался для меня, поэтому я тестировал его на Python, чтобы очистить его для себя.
Прежде всего PEP для varargs здесь.
Вот пример программы, основанной на двух ответах от Дэйва и Дэвида Бергера, а затем на выходе, только для уточнения.
def func( *files ):
print files
for f in files:
print( f )
if __name__ == '__main__':
func( *['file1','file2','file3'] ) #Is treated like func('file1','file2','file3')
func( 'onestring' )
func( 'thing1','thing2','thing3' )
func( ['stuff1','stuff2','stuff3'] )
И полученный результат;
('file1', 'file2', 'file3')
file1
file2
file3
('onestring',)
onestring
('thing1', 'thing2', 'thing3')
thing1
thing2
thing3
(['stuff1', 'stuff2', 'stuff3'],)
['stuff1', 'stuff2', 'stuff3']
Надеюсь, это поможет кому-то другому.