4

I was recently working on some prototype code in Python. The code worked great, then I realized that I needed a little more feedback from one of my functions so I changed the return statement from

return x

to

return (x,y)

Then going back to refactor existing code I realized that unless I search for invocation of this function across entire of the code base I won't know of any problems until run-time (and if this is some marginal case) barely ever and risking the program crashing due to uncaught exception resulting in operations on mismatched types. I contrast this with statically typed languages, where at compile time I get told about all places where the return doesn't mismatches expected type.

So I was wondering whether there is some conventional wisdom associated with the return types in Python to avoid this grepping through code nonsense.

P.S> Obviously better design patterns would solve this problem or not using duck typed language, but sometimes one comes across a case when you got to change the return type.

  • Just a nitpick - python is strongly typed. Someone correct me if I'm wrong, but I believe what you're describing is statically typed languages. – ubomb Jul 29 '14 at 15:15
  • @ubomb: That post seems a bit misleading... All runtime objects have a type, regardless of their ... erm, strongness. Dynamic binding is late (at runtime), rather than early (at compile time) static binding. – Robert Harvey Jul 29 '14 at 15:17
  • @ubomb you right I don't mean strong, I mean statically typed. But that's not my question. – Alex Jul 29 '14 at 15:17
  • 1
    Cross-posted from Stack Overflow: Good practise for returns in Python – Martijn Pieters Jul 29 '14 at 15:22
  • 4
    There's no design pattern that'll turn a dynamically-typed language into a statically-typed one. The best you can do is get an IDE that can do the refactoring for you. – Doval Jul 29 '14 at 15:37
2

PyCharm (the community version is FOSS) will do a pretty good job of finding all calls to your function (Alt-F7), so you can easily see how it's called. Of course, being a dynamic language it can't untangle truly horrible code, but your use case should be fine.

Another mechanism which may fit your case better (since returning two things is a common way for code to smell of missing objects) is to return an object with two attributes.

  • 6
    A tuple is a perfectly good object with two attributes. But once you find yourself wondering what is where in your tuple, it's probably time to make the parts named instead of indexed. Often namedtuple suffices. – 9000 Jul 29 '14 at 21:18
  • I didn't know about the namedtuple constructs. Thanks – Alex Jul 30 '14 at 14:27
  • Named tuples are great. Another nice alternative are attribute-accessible dictionaries, such as stuf. While having a little more overhead than named tuples, they are schemaless, requiring less up-front definition and no updating if you add further members. They also serialize nicely to JSON dictionaries, whereas named tuples serialize to arrays, losing their attribute names. Both structures are useful. As long as you're adding named tuples to your toolbox, also consider attribute-accessible dicts. – Jonathan Eunice Aug 15 '14 at 15:41
0

In addition to what the 2 other answers say (refactoring tool/test suite/return an object that behaves like your original return value), a static type checker like mypy would catch this immediately, because you are changing the type of the function.

A very simplified example:

def foo() -> Tuple[int, str]:
    original_return_value = 23
    return original_return_value, "additional information"

a = foo() / 3  # type error: Tuple can't be divided by int

Of course, this won't help you much with an existing code base.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.