Как проверить типы, содержащиеся в списке?

Я хочу сделать следующее без определения функции:

if isinstance(x,(list,tuple)) and every_element_isinstance(x,basestring):
   foobar

ie: implementing type checking

Есть ли для этого сокращение /builtin?


person user1358    schedule 06.01.2013    source источник
comment
Почему вы не хотите определить функцию?   -  person Ned Batchelder    schedule 06.01.2013


Ответы (4)


Я думаю, что это лучшее решение (если я понимаю вопрос)

if isinstance(x, (list, tuple)) and all(isinstance(i, basestring) for i in x):
    #do whatever
person Volatility    schedule 06.01.2013
comment
Это решение без понимания списка ([... for ...]) лучше, особенно для медленных условий, потому что понимание списка оценивает все условия, даже если первое из них не выполняется. - person hynekcer; 06.01.2013
comment
isinstance(x, collections.Iterable) может быть здесь больше подходит - person Eric; 06.01.2013

if isinstance(x, (list, tuple)) and all([isinstance(i, basestring) for i in x]):
    foobar

Удивительно, но понимание списка с [ ... ] здесь быстрее, чем без, как с короткими, так и с длинными списками:

короткие списки:

>>> timeit('isinstance(x, (list, tuple)) and all(isinstance(i, basestring) for i in x)', "x=['a','b','c']")
2.7594685942680144
>>> timeit('isinstance(x, (list, tuple)) and all(isinstance(i, basestring) for i in x)', "x=['a','b','c']")
2.8013695153947538
>>> timeit('isinstance(x, (list, tuple)) and all([isinstance(i, basestring) for i in x])', "x=['a','b','c']")
2.4351678506033068
>>> timeit('isinstance(x, (list, tuple)) and all([isinstance(i, basestring) for i in x])', "x=['a','b','c']")
2.4491469896721583

длинные списки:

>>> timeit('isinstance(x, (list, tuple)) and all(isinstance(i, basestring) for i in x)', "x=['a','b','c'] * 1000", number=1000)
1.3357901657891489
>>> timeit('isinstance(x, (list, tuple)) and all(isinstance(i, basestring) for i in x)', "x=['a','b','c'] * 1000", number=1000)
1.3305278872818462
>>> timeit('isinstance(x, (list, tuple)) and all([isinstance(i, basestring) for i in x])', "x=['a','b','c'] * 1000", number=1000)
1.2626525921055531
>>> timeit('isinstance(x, (list, tuple)) and all([isinstance(i, basestring) for i in x])', "x=['a','b','c'] * 1000", number=1000)
1.2881240045551863
person BrtH    schedule 06.01.2013
comment
@Volatility через секунду после того, как я отправил свой ответ, я увидел ваше всплывающее окно. Великие умы думают одинаково :D - person BrtH; 06.01.2013
comment
какой из них я должен принять тогда? Я имею в виду, что оба идеальны - person user1358; 06.01.2013
comment
Ну, у Volatility меньше репутации, так что... извините, БртХ - person user1358; 06.01.2013
comment
Ха-ха, спасибо, я как раз собирался сказать, что мое решение лучше, потому что в нем на два символа меньше :P - person Volatility; 06.01.2013
comment
на самом деле я должен был выбрать BrtH, так как в Volatility есть опечатка - person user1358; 06.01.2013
comment
Это хорошая аргументация для вас обоих, ха-ха! Но у меня есть еще один плюс, так что, по крайней мере, я получаю репутацию :P - person BrtH; 06.01.2013
comment
@Volatility Я решил проверить, какой ответ лучше. Удивительно, но я выигрываю, хотя это не существенная разница. - person BrtH; 06.01.2013
comment
А что, если, как сказал Хайнексер, первый элемент не является строкой? - person Volatility; 06.01.2013
comment
@Volatility хорошо, я провел несколько дополнительных тестов: в этом случае все почти наоборот. Как для маленьких, так и для длинных списков, если первый элемент имеет тип int, вы выигрываете, если последний элемент представляет собой тип int, я выигрываю. Если нестроковый элемент находится в середине списка, я выиграю в коротком списке, а вы выиграете в длинном списке. - person BrtH; 06.01.2013
comment
Что в конечном итоге означает, что мое решение лучше, потому что оно короче! :П - person Volatility; 06.01.2013

Нет встроенного определения универсальных типов. Но существует множество библиотек проверки, которые могут имитировать эту функциональность.

Пример использования https://github.com/alecthomas/voluptuous:

>>> from voluptuous import Schema
>>> s_list = Schema([basestring]) # only strings in a list are allowed
>>> s_list("hello") 
...
voluptuous.InvalidList: expected a list
>>> s_list([123])
...
voluptuous.InvalidList: invalid list value @ data[0]
>>> s_list(["correct"])
["correct"] # returns the object, if validation was successful

Несколько дней назад в эту библиотеку была добавлена ​​поддержка кортежа:

>>> s_tuple = voluptuous.Schema((basestring, ))

Теперь объедините два, чтобы получить результат:

>>> from voluptuous import any

# - this is now equivalent to your code
# - raises Exceptions on invalid input
>>> schema = Schema(any(s_list, s_tuple))

Это даже немного быстрее, чем double-isinstance:

>>> from timeit import timeit

>>> timeit('(schema(i) for i in x)', "x=['a','b','c']")
0.679318904876709

>>> timeit("""
        (isinstance(x, (list, tuple)) 
         and all(isinstance(i, basestring)) for i in x)""", "x=['a','b','c']")
0.7801780700683594
person miku    schedule 06.01.2013

С сладострастным «0.8.7» вы можете обновить ответ от miku и пропустить «часть кортежа»:

>>> from voluptuous import Schema
>>> from timeit import timeit
>>> s_list = Schema([basestring]) # only strings in a list are allowed
>>> timeit('(s_list(i) for i in x)', "x=['a','b','c']")
0.503572940826416
>>> timeit("(isinstance(x, (list, tuple)) and all(isinstance(i, basestring)) for i in x)", "x=['a','b','c']")
0.5400209426879883
person Jakub    schedule 16.11.2015