5

Possible Duplicate:
Tools for static type checking in Python

For most part I love the fact that you can pick up any type and drop it where you like in Python and just let the Duck typing take over. But how would one stop the darn thing from passing Compile time. Is there a way to enforce some sort of sanity checks when required at compile time, without resorting to Unit Tesing.

Community
  • 1
  • 1
WeNeedAnswers
  • 4,620
  • 2
  • 32
  • 47

8 Answers8

4

Use a separate tool like Pychecker to warn you about things like usages of non-existent methods or properties. This isn't part of compilation, but you could enforce it as part of your own process, such as a pre-commit hook in your VCS.

Ben James
  • 121,135
  • 26
  • 193
  • 155
3

No. The Python compiler doesn't (and, generally, can't) even know if you spelled variable names correctly, much less what types might be pup in each variable, object attribute, collection slot, etc. And that's not just because the people writing it have other priorities, it is very hard to impossible with most code. For some very simple cases, static analyzers may be able to attempt something like this. But practically, it's impossible.

3

The compiler doesn't have type information in Python; however, the possibility of adding optional annotations to the language that would give the compiler that information has been discussed, here for instance.

In the meantime, I recommend looking into PyChecker, which may do some of what you want.

plasticsaber
  • 232
  • 1
  • 4
1

Python doesn't really have a well-defined "compile-time" that other, static, languages have.

You can use isinstance() and type() to verify that your object is an instance of a class you're expecting however.

yan
  • 20,644
  • 3
  • 38
  • 48
  • +1 for this. It is important to understand that in Python, a class or function definition is *code that is executed.* This knowledge will make a lot of crazy-seeming things make perfect sense. – kindall Jul 27 '11 at 20:50
  • Yeah I know about these, just thought maybe there was a sneaky little option for enforcing "stupid dumb shmuck me" from doing something stupid and being warned about it before I actually doing it. Hey maybe what I need is a time machine. – WeNeedAnswers Jul 27 '11 at 21:10
1

You can just make the first line of everything resemble:

if not all(isinstance(a, b) for a, b in zip(((x, int), (y, str), (z, float))))

You could use a package like http://code.enthought.com/projects/traits/ that allows you to explicitly declare types.

You could write your code in http://cython.org/.

agf
  • 171,228
  • 44
  • 289
  • 238
  • Cython isn't for getting static typing, it's for writing code that runs between C and Python. In fact, the Cython compiler treats all Python objects as if of a single type (`object`). –  Jul 27 '11 at 20:53
  • I know, but it's Python-like and you can declare types. If he only wanted to do this for some specific code it's a possible solution. – agf Jul 27 '11 at 20:53
  • No, all Python objects are (much like in Python itself) "typed" as having a single ophaque type claiming to support all operations at compiletime and failing for most at runtime. The `int` and `float` etc. parts are just C values implicitly converted to from some Python objects and *very* limited. You'd have to write your own extension types, which is simply overkill and needlessly hard. –  Jul 27 '11 at 20:55
  • You're saying if in Cython I did `def work_with_binary_data(bytes binary_data)` and it was called, from other Cython code, with some other type than bytes (declared as such in Cython), it would only fail at runtime not compile time? – agf Jul 27 '11 at 21:07
  • Ah, right, string handling is also included at the level of Cython's type system. That's pretty much (unless I'm forgetting yet another type) the exception to the "only C and user-defined extension types". There is no `list` or `set` type, for instance, only `object`. –  Jul 27 '11 at 21:11
  • Right here is a guide to adding type checking to a Python file with Cython: http://docs.cython.org/src/tutorial/pure.html#augmenting-pxd – agf Jul 27 '11 at 21:19
  • 2
    Oh. I have to admit, my previous statements were wrong. I apologize for spreading FUD, although I still think using Cython for having some static typing is impractical and semtantically wrong. –  Jul 27 '11 at 21:21
  • Yes, well that's why I recommended two other Pythonic solutions first, the "standard" way and a widely used and well supported library. – agf Jul 27 '11 at 21:27
1

Python doesn't have anything like that, because compile is initialization time. You can use assert statements to enforce that specific types are being passed to your functions, i.e. assert type(foo) == list, but that's somewhat unpythonic, as it defeats the point of duck typing in the first place. What is pythonic is checking to make sure the object you're getting has the method you need. For example, if you need to iterate over the object, try this:

assert '__iter__' in dir(obj)
Colin Valliant
  • 1,899
  • 1
  • 13
  • 20
1

You can abuse decorators, to add warnings for unusual types in debug mode:

import warnings
import functools
import numbers

debug = True

class TypeWarning(Warning):
    pass

def warn_types(*pos_types):
    def decorator(func):
        if not debug:
            return func
        @functools.wraps(func)
        def wrapper(*args):
            for i, (x, t) in enumerate(zip(args, pos_types)):
                if not isinstance(x, t):
                    warnings.warn("Expected %s got %s for argument %d of %s"
                                        % (t.__name__, x.__class__.__name__,
                                           i, func.__name__),
                                  category=TypeWarning, stacklevel=2)
            return func(*args)
        return wrapper
    return decorator


@warn_types(numbers.Number, numbers.Number)
def add(x, y):
    return x + y

This produces warnings for the programmer without breaking the functionality, and they can be turned off by turning off the debug mode. They can be also removed by a simple search-replace after you've finished coding your project.

>>> print add(3, 4)
7
>>> print add("a", "b")
__main__:1: TypeWarning: Expected Number got str for argument 0 of add
__main__:1: TypeWarning: Expected Number got str for argument 1 of add
ab

Extending this for keyword arguments is non-trivial in the general case, unless you're on Python 3 and can take advantage of annotations, in case it can become very simple.

Rosh Oxymoron
  • 20,355
  • 6
  • 41
  • 43
0

I think you just want a quick type check, right?

I'll answer with a quick demo:

>>> m = 7
>>> m.__class__
<type 'int'>
>>> n = 6
>>> o = 6.6
>>> m.__class__ == n.__class__
True
>>> m.__class__ == o.__class__
False
>>> isinstance(o, int)
False
>>> isinstance(m, int)
True
>>> 

Hope that makes sense.

Vasiliy Sharapov
  • 997
  • 1
  • 8
  • 27
  • no, I know about this sort of stuff. I thought that there maybe a nice little compile time option, to stop me doing something stupidly nutty. – WeNeedAnswers Jul 27 '11 at 21:08