Как я могу сказать, является ли переменная python строкой или списком?
у меня есть процедура, которая принимает список строк в качестве параметра, но я хотел бы поддержать передачу в одной строке и преобразование ее в список одной строки. Например:
def func( files ):
for f in files:
doSomethingWithFile( f )
func( ['file1','file2','file3'] )
func( 'file1' ) # should be treated like ['file1']
как моя функция может определить, была ли передана строка или список? Я знаю, что есть type функция, но есть "более подходящие для Python" способ?
8 ответов:
Ну,нет ничего необычного в проверке типа. Сказав это, если вы готовы положить небольшую нагрузку на абонента:
def func( *files ): for f in files: doSomethingWithFile( f ) func( *['file1','file2','file3'] ) #Is treated like func('file1','file2','file3') func( 'file1' )Я утверждаю, что это более подходящие для Python в том, что "явное лучше, чем неявное". Здесь есть, по крайней мере, признание со стороны вызывающего абонента, когда этот вход уже в виде списка.
лично мне не очень нравится такое поведение - оно мешает набирать утку. Можно утверждать, что он не подчиняется мантре "явное лучше, чем неявное". Почему бы не использовать синтаксис varargs:
def func( *files ): for f in files: doSomethingWithFile( f ) func( 'file1', 'file2', 'file3' ) func( 'file1' ) func( *listOfFiles )
Я бы сказал, что самый Python'y способ-заставить пользователя всегда передавать список, даже если в нем есть только один элемент. Это делает его действительно очевидным
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)действительно, я предлагаю просто требовать список, даже с одним файлом (в конце концов, он требует только двух дополнительных символов!)
def func(files): for f in files if not isinstance(files, basestring) else [files]: doSomethingWithFile(f) func(['file1', 'file2', 'file3']) func('file1')
Если у вас есть больше контроля над абонентом, то один из других ответов лучше. У меня нет такой роскоши в моем случае, поэтому я остановился на следующем решении (с оговорками):
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этот подход будет работать для случаев, когда вы имеете дело с знать список типов, которые отвечают вышеуказанным критериям. Однако некоторые типы последовательностей будут пропущены.
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']надеюсь, что это полезно для кого-то еще.
Comments