Reputation: 639
In C++ and C# and others, you can overload or adjust the return type to match the input types. Using Python I find references that the return type should be consistent regardless. Like in this question
Now for my code that wants to match return type to param type
def myUpper(what_is_this_thing):
try:
return what_is_this_thing.upper()
except AttributeError:
try:
return {k:what_is_this_thing[k].upper() for k in what_is_this_thing}
except TypeError:
return [x.upper() for x in what_is_this_thing]
print myUpper('test')
print myUpper(['test', 'and more'])
print myUpper({'one':'test', 'two': 'and more'})
print myUpper(['test', 1000])
output
TEST
['TEST', 'AND MORE']
{'two': 'AND MORE', 'one': 'TEST'}
An exception is rased because the payload does not have a upper method
So how bad is this python sin? I mostly still work in 2.7 I know 3.3 has type hints, learning that will need to wait for later in the summer.
Anyone have a less sinful way to achieve most of the benefits? or a coherent argument why this should not be done?
Addendum:
Other than the Python3 Moses which I like. I feel compelled to find if this question is best answered with something like in python 2.7
def myUpper(s):
return s.upper()
print myUpper('test')
print [s.myUpper() for s in 'test', 'and more'] d = { 'one':'test', 'two': 'and more'}
print {k:d[k].myUpper() for k in d}
In summary spread comprehension stuff out in the code even if is quite common. Choose proliferation of comprehension over obscure return data types?
I suspect I would remove 400+ comprehension lines in the final code if I did it with adjusting return types. But if that is too strange then so be it.
It comes down to readability ver violation of the unwritten rule about 1 function 1 return type.
Upvotes: 2
Views: 603
Reputation: 22021
Putting my five cents there:
hanlders = {
str: (lambda what_is_this_thing: what_is_this_thing.upper()),
dict: (lambda what_is_this_thing: {k:what_is_this_thing[k].upper() for k in what_is_this_thing}),
list: (lambda what_is_this_thing: [x.upper() for x in what_is_this_thing]),
}
print handlers[type(what_is_this_thing)](what_is_this_thing)
Upvotes: 1
Reputation: 78546
If you're looking to have some consistency of the return type with the argument (precisely, first argument), you can create overloaded implementations of your function with functools.singledispatch
; one of the reasons I'll say you start moving to Python 3:
from functools import singledispatch
@singledispatch
def my_upper(what_is_this_thing):
return what_is_this_thing.upper()
@my_upper.register(list)
def _(this_is_a_list):
...
return this_is_also_a_list
@my_upper.register(dict)
def _(this_is_a_dict):
...
return this_is_also_a_dict
Upvotes: 3
Reputation: 10782
You could use isinstance
- and passing the keys / values of a dict as well as the items of a list recursively to the function will handle more types:
def myUpper(o):
if(isinstance(o, str)):
return o.upper()
elif(isinstance(o, list)):
return [myUpper(x) for x in o]
elif(isinstance(o, dict)):
return {myUpper(k):myUpper(v) for k,v in o.items()}
else:
return o
Upvotes: 0
Reputation: 3002
You can actually check the type instead of relying on exceptions.
v = 'one'
if type(v) == str:
# Treat it as a string
elif type(v) == list:
# Treat it as a list
elif type(v) == dict:
# Treat is as a dict
Upvotes: 0