It is not the type(..) function that does not work: the error occurs when constructing the list.
When a compiler/interpreter reads code, it will aim to generate an abstract syntax tree according to the grammar of the language. ! and # are simply invalid grammar. The # is interpreted as the start of a comment, so the interpreter will read:
L = [1, "123", !,
But that does not make any sense either since ! is not valid, and even if you would remove the !, then Python will still complain it cannot find a matching ] (to close the list).
Now let's assume you sort that out, there is another problem: what with subclassing? One can for instance subclass a string. Do you count it as a str or other? The problem is more troublesome because Python supports multiple inheritance: something can be a string and a bool at the same time. Let us assume we only count real strings and not subclasses, then we can write the following code:
def count_types(data):
the_types = [int,float,str,bool]
result = [0]*(len(the_types)+1)
for x in data:
tyx = type(x)
for idx,ty in enumerate(the_types):
if tyx is ty:
result[idx] += 1
break
else:
result[-1] += 1
return result
This would produce:
>>> count_types([1, "123", 2.0, True, False, [1,2]])
[1, 1, 1, 2, 1]
Nevertheless it is weird that you want to return a list without context, and furthermore that you only count specific types. I guess a more elegant and faster solution, is to generate a Counter with types:
from collections import Counter
result = Counter(type(x) for x in data)
This generates:
>>> Counter(type(x) for x in data)
Counter({<class 'bool'>: 2, <class 'list'>: 1, <class 'str'>: 1, <class 'float'>: 1, <class 'int'>: 1})
!and#are not valid objects to begin with...collections.Counter(map(type, L))?