Python Forum

Full Version: testing if this is a container type
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
in a function being passed an argument, it might be a single data type or it might be a container of some type. i need to do different callbacks depending on that. i am wondering if there is a way to test of some given argument is a container or not. even if it some programmer created type (it's just going to be passed back with some other data, so i don't need to understand that data any more than that). does anyone know how to do such a test?
You should really checkout the collections.abc module.
(Jan-24-2019, 07:01 PM)Skaperen Wrote: [ -> ]in a function being passed an argument, it might be a single data type or it might be a container of some type. i need to do different callbacks depending on that.

in addition to ichabood's suggestion, I would recommend to look at @functools.singledispatch
I'm not sure how that happened, buran, but you seem to have quoted Skaperen and attributed it to me.

Edit: If you select text from one post, and click the quote highlighted button for another post, it quotes the first poster and attributes it to the second poster.
(Jan-24-2019, 07:53 PM)ichabod801 Wrote: [ -> ]'m not sure how that happened, buran, but you seem to have quoted Skaperen and attributed it to me.

Edit: If you select text from one post, and click the quote highlighted button for another post, it quotes the first poster and attributes it to the second poster.
yes, I know that, my error, sorry :-) Now I will fix it :-)
Here is an example with @functools.singledispatch

import collections.abc
import functools

@functools.singledispatch
def foo(arg):
    print("that's not container", type(arg))

@foo.register(collections.abc.Container)
def _(arg):
    print('Now that is container', type(arg))


test_items = [int(), str(), dict(), list()]

for item in test_items:
    foo(item)
Output:
that's not container <class 'int'> Now that is container <class 'str'> Now that is container <class 'dict'> Now that is container <class 'list'>
EDIT: Fixed the import - collections.abc instead of just collections. Importing just collections was giving an error with 3.7, although at home I think I test the code with 3.5. collections.abc was part of collections before 3.3
oh dear, this program i'm doing needs to have str not be a container. yeah, i know it technically is a container. i didn't think about that, yet. but, buran's example made obvious. it's simple enough to check for str first.
You can always register separate callback for str. It will take precedence over the callback for the abstract class. Also it will propagate for any custom class that inherit from str.
import collections.abc
import functools
 
@functools.singledispatch
def foo(arg):
    print("that's not container", type(arg))
 
@foo.register(collections.abc.Container)
def _(arg):
    print('Now that is container', type(arg))
    
@foo.register(str)
def _(arg):
    print("that's str", type(arg))
    
class Foo(str):
    pass
 
 
test_items = [int(), str(), dict(), list(), Foo()]
 
for item in test_items:
    foo(item)
Output:
that's not container <class 'int'> that's str <class 'str'> Now that is container <class 'dict'> Now that is container <class 'list'> that's str <class '__main__.Foo'> >>>
Note that you can use different names for the registered callbacks so that you can distinguish and check which callback will be used for certain class.