4

I'm a long time programmer in C# but have been coding in Python for the past year. One of the big hurdles for me was the lack of type definitions for variables and parameters. Whereas I totally get the idea of duck typing, I do find it frustrating that I can't tell the type of a variable just by looking at it. This is an issue when you look at someone else's code where they've used ambiguous names for method parameters (see edit below).

In a few cases, I've added asserts to ensure parameters comply with an expected type but this goes against the whole duck typing thing.

On some methods, I'll document the expected type of parameters (eg: list of user objects), but even this seems to go against the idea of just using an object and let the runtime deal with exceptions.

What strategies do you use to avoid typing problems in Python?

Edit: Example of the parameter naming issues: If our code base we have a task object (ORM object) and a task_obj object (higher level object that embeds a task). Needless to say, many methods accept a parameter named 'task'. The method might expect a task or a task_obj or some other construct such as a dictionary of task properties - it is not clear. It is them up to be to look at how that parameter is used in order to work out what the method expects.

2
  • "It is then up to me to look at how that parameter is used in order to work out what the method expects." How is this a problem? Isn't this true of every language? I'm not clear on why the API documentation and comments aren't enough. Every language depends on API documentation and comments.
    – S.Lott
    Feb 9, 2011 at 11:04
  • 1
    I think the issue (as noted below) could just be the pain of dealing with other people's undocumented code. A language like C# gives a few more hints as to what is going on by having types noted but the real solution here is probably just to document the parameters and behaviour and implement some naming standards.
    – dave
    Feb 9, 2011 at 12:46

4 Answers 4

8

As of Python 3, you can annotate at least function parameters and return values with types:

def foo(task: 'task') -> 'bool':
    pass

The type annotation can be any valid Python expression. In this case I used strings, but you can just as well use integers, dicts, lists, or – and that's the interesting bit – classes.

6
  • 2
    One should point out, this works only for Python >= 3.0 Feb 9, 2011 at 11:25
  • @Lenny222: Yep, thanks for pointing that out. Generally, if I don't mention specific versions in any of my answers, I assume the latest published one (in the case of Python that would be 3.2 right now, although for this particular answer any version of 3.x is fine). Conversely, if a question doesn't mention a version, I assume the latest supported version, which would be 3.1. (Personally, I think Ruby 1.9, Python 3000, C# 4, ECMAScript 5.1 and Scala 2.9 are such big improvements that you'd need a good reason not to use them.) Feb 9, 2011 at 14:15
  • 5
    In general the latest version would make sense, sadly delay in the adoption of Python 3, means we need to be clear about the differences. Feb 9, 2011 at 15:08
  • In general i agree. It's just that some people (including me at work) are tied to an older version, because of a commercial third-party software. Don't ask. Feb 9, 2011 at 15:40
  • @Lenny222: Don't get me wrong, I understand that perfectly well. Being a Rubyist, I myself am stuck on Python 2.7 (as a Python user that is), because I simply don't know enough about Python to figure out how to do my own Windows build of PIL, so I'm stuck with whatever PythonWare throws at me. Only for toy scripts where all the code is under my control, do I use Python 3.2. With Ruby, however, I've been on 1.9 since before it was released, because I know how to fix stuff when it breaks. I'm currently pondering doing a project where the only platforms available would be Java 1.4(!) or RPG. Feb 9, 2011 at 17:32
2

Write unit tests. They are also useful for typed languages, but in dynamic typed languages such as Python or Smalltalk unit tests give you the added bonus of type checking.

I'm not saying you should check types in the unit test, but that the test will probably fail if you use the wrong types.

edit:

But maybe I misunderstood your question. Are you having real productivity problems with weak typing in Python? Or are you just worried you will?

If its the former, go with TDD, it will also give you confidence in the code you are writing. If the latter, just go ahead and don't worry to much. When I first learned about Smalltalk I was coming from Java, and the weak typing issue surprised me. So the first thing I asked a veteran Smalltalk coder was:

-don't you have lot's of type-related runtime bugs?

-no, that was never a problem for me

Usually the weak-typed languages are more productive than the strong-typed, so any inconvenniences with typying is not a big deal.

2
  • 1
    I feel my productivity is not what it could be. When I come across a chunk of someone else's code, I feel it takes me too long for me to work out what is expected by the method. Once I understand the parameters in play, the rest is easy.
    – dave
    Feb 9, 2011 at 1:21
  • Ok, so it's mostly using other people's code. Feb 9, 2011 at 1:47
2

I can't tell the type of a variable just by looking at it.

Why would you need to?

ambiguous names for method parameters.

Not sure what this could possibly mean. You'll have to provide examples.

I've added asserts to ensure parameters comply with an expected type but this goes against the whole duck typing thing.

Worse. It can break a perfectly good program by checking for too small a subset of legitimate types. Done badly, it makes subclass extensions difficult.

I'll document the expected type of parameters (eg: list of user objects)

Good.

but even this seems to go against the idea of just using an object and let the runtime deal with exceptions.

That's false. Documenting the interface to an object required by a method is a good thing. It doesn't "go against" anything.

def foo( self, some_object ):
    """some_object must have methods x() and y()."""
    some_object.x()
    some_object.y()

The docstring doesn't go against anything. It's perfectly correct. Perhaps unhelpful, but still correct.

What strategies do you use to avoid typing problems in Python?

You should choose better terms. There are no typing "problems".

What you're asking about is -- perhaps -- better called the transition discomfort. You have legacy habits built up around C#. It takes a while to get over those habits.

You don't mention unit testing. Why not?

6
  • Fair point on 'weak typing' - I've updated the question. Why would I want to know the type of a parameter? Because I wish to call methodX and it expects a parameter called task (see example in edit). I need to know what to pass. Obviously parameter comments would help here. I get the problems are problems in me, Python acts in the way that it was designed to act. I am trying to work out how best to work with Python's design.
    – dave
    Feb 8, 2011 at 23:28
  • re Unit testing: I'm trying to increase my coding productivity - you can't test what you have not written yet. Unit testing comes after that. For low level methods, I've also set up scripted testing suites.
    – dave
    Feb 8, 2011 at 23:44
  • 1
    Actually, the unit testing techique (TDD) that is usually proposed is 1- write test that fails, 2- write code until test passes, 3- refactor. That is, you write the test before coding the feature, probably using mocks. It may seem less productive, but the test will tell you if future refactorings are breaking something. Feb 9, 2011 at 0:18
  • 4
    @Dave: Re: "you can't test what you have not written yet." Obviously you haven't had enough kool-aid yet; that's exactly what you're supposed to be doing! First you write the test that tests what your code is supposed to do, then you write code that will pass the test. Feb 9, 2011 at 0:21
  • The answer asked why I had not mentioned unit testing. It did not ask why I am not writting test plans nor make any mention of TDD. That being said, in order to write a test plan (or write code), you still need to understand the parameters to a method - thus the question.
    – dave
    Feb 9, 2011 at 0:32
1

The types a function expects should be ideally documented in the function's docstring (or by using the Python3 annotations). Then it's up to the caller of the function to provide the right kinds of ducks. This has the advantage that many Python IDEs use the first line of the docstring as a context help when hovering over a function/method name (in situations where the IDE is able to determine the type from context).

In most cases, the parameter names should make the expected type clear enough in the context of the given module. Your example sounds like you need to agree on some better conventions for parameter names instead of just using "task" for everything.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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