I am currently translating some Python to F#, specifically neural-networks-and-deep-learning .
To make sure the data structures are correctly translated the details o
One way to do it by hand would be:
def type_spec_iterable(obj, name):
tps = set(type_spec(e) for e in obj)
if len(tps) == 1:
return name + "<" + next(iter(tps)) + ">"
else:
return name + "<?>"
def type_spec_dict(obj):
tps = set((type_spec(k), type_spec(v)) for (k,v) in obj.iteritems())
keytypes = set(k for (k, v) in tps)
valtypes = set(v for (k, v) in tps)
kt = next(iter(keytypes)) if len(keytypes) == 1 else "?"
vt = next(iter(valtypes)) if len(valtypes) == 1 else "?"
return "dict<%s, %s>" % (kt, vt)
def type_spec_tuple(obj):
return "tuple<" + ", ".join(type_spec(e) for e in obj) + ">"
def type_spec(obj):
t = type(obj)
res = {
int: "int",
str: "str",
bool: "bool",
float: "float",
type(None): "(none)",
list: lambda o: type_spec_iterable(o, 'list'),
set: lambda o: type_spec_iterable(o, 'set'),
dict: type_spec_dict,
tuple: type_spec_tuple,
}.get(t, lambda o: type(o).__name__)
return res if type(res) is str else res(obj)
if __name__ == "__main__":
class Foo(object):
pass
for obj in [
1,
2.3,
None,
False,
"hello",
[1, 2, 3],
["a", "b"],
[1, "h"],
(False, 1, "2"),
set([1.2, 2.3, 3.4]),
[[1,2,3],[4,5,6],[7,8,9]],
[(1,'a'), (2, 'b')],
{1:'b', 2:'c'},
[Foo()], # todo - inheritance?
]:
print repr(obj), ":", type_spec(obj)
This prints:
1 : int
2.3 : float
None : (none)
False : bool
'hello' : str
[1, 2, 3] : list<int>
['a', 'b'] : list<str>
[1, 'h'] : list<?>
(False, 1, '2') : tuple<bool, int, str>
set([2.3, 1.2, 3.4]) : set<float>
[[1, 2, 3], [4, 5, 6], [7, 8, 9]] : list<list<int>>
[(1, 'a'), (2, 'b')] : list<tuple<int, str>>
{1: 'b', 2: 'c'} : dict<int, str>
[<__main__.Foo object at 0x101de6c50>] : list<Foo>
There's a question of how far you want to take it, and how deeply to check, with trade-offs between speed and accuracy. For example, do you want to go through all the items in a large list? Do you want to handle custom types (and tracking down common ancestors of those types)?
Worth a read, though I'm not sure it's applicable, this PEP on type hints.
As I commented, this is impossible in Python, because lists are untyped.
You can still pretend to do it:
def typ(something, depth=0):
if depth > 63:
return "..."
if type(something) == tuple:
return "<class 'tuple': <" + ", ".join(typ(ding, depth+1) for ding in something) + ">>"
elif type(something) == list:
return "<class 'list': " + (typ(something[0], depth+1) if something else '(empty)') + ">"
else:
return str(type(something))
That returns the string <class 'tuple': <<class 'list': <class 'list': <class 'int'>>>,<class 'list': <class 'str'>>>>
for your example.
edit: To make it look more like F# you could do this instead:
def typ(something, depth=0):
if depth > 63:
return "..."
if type(something) == tuple:
return " * ".join(typ(ding, depth+1) for ding in something)
elif type(something) == list:
return (typ(something[0]) if something else 'empty') + " []"
else:
return str(type(something, depth+1)).split("'")[1]
which will return int [] [] * str []
in your example.