On 1/8/2016 6:04 PM, Guido van Rossum wrote:
At Dropbox we're trying to be good citizens and we're working towards introducing gradual typing (PEP 484) into our Python code bases (several million lines of code). However, that code base is mostly still Python 2.7 and we believe that we should introduce gradual typing first and start working on conversion to Python 3 second (since having static types in the code can help a big refactoring like that).
Since Python 2 doesn't support function annotations we've had to look for alternatives. We considered stub files, a magic codec, docstrings, and additional `# type:` comments. In the end we decided that `# type:` comments are the most robust approach. We've experimented a fair amount with this and we have a proposal for a standard.
The proposal is very simple. Consider the following function with Python 3 annotations:
def embezzle(self, account: str, funds: int = 1000000, *fake_receipts: str) -> None: """Embezzle funds from account using fake receipts.""" <code goes here>
An equivalent way to write this in Python 2 is the following:
def embezzle(self, account, funds=1000000, *fake_receipts): # type: (str, int, *str) -> None """Embezzle funds from account using fake receipts.""" <code goes here>
I find the this separate signature line to be at least as readable as the intermixed 3.x version. I noticed the same thing as Lemburg (no runtime .__annotations__ attributes, but am not sure whether adding them in 2.x code is a good or bad thing.
There are a few details to discuss:
- Every argument must be accounted for, except 'self' (for instance methods) or 'cls' (for class methods). Also the return type is mandatory. If in Python 3 you would omit some argument or the return type, the Python 2 notation should use 'Any'.
- If you're using names defined in the typing module, you must still import them! (There's a backport on PyPI.)
- For `*args` and `**kwds`, put 1 or 2 starts in front of the corresponding type annotation. As with Python 3 annotations, the annotation here denotes the type of the individual argument values, not of the tuple/dict that you receive as the special argument value 'args' or 'kwds'.
- The entire annotation must be one line. (However, see https://github.com/JukkaL/mypy/issues/1102.)
To me, really needed.
We would like to propose this as a standard (either to be added to PEP 484 or as a new PEP) rather than making it a "proprietary" extension to mypy only, so that others in a similar situation can also benefit.
Since I am personally pretty much done with 2.x, the details do not matter to me, but I think a suggested standard approach is a good idea. I also think a new informational PEP, with a reference added to 484, would be better. 'Type hints for 2.x and 2&3 code' For a helpful tool, I would at least want something that added a template comment, without dummy 'Any's to be erased, to each function. # type: (, , *) -> A GUI with suggestions from both type-inferencing and from a name -> type dictionary would be even nicer. Name to type would work really well for a project with consistent use of parameter names. -- Terry Jan Reedy