2

I come from static-type programming and I'm interested in understanding the rationale behind dynamic-type programming to check if dynamic-type languages can better fit my needs.

I've read about the theory behind duck programming. I've also read that unit testing (desirable and used in static-type programming) becomes a need in dynamic languages where compile-time checks are missing.

However, I'm still afraid to miss the big picture. In particular, how can you check for a mistake where a variable type is accidentally changed ?

Let's make a very simple example in Python:

#! /usr/bin/env python

userid = 3
defaultname = "foo"

username = raw_input("Enter your name: ")
if username == defaultname:
    # Bug: here we meant userid...
    username = 2

# Here username can be either an int or a string
# depending on the branch taken.
import re
match_string = re.compile("oo")
if (match_string.match(username)):
        print "Match!"

Pylint, pychecker and pyflakes do not warn about this issue.

What is the Pythonic way of dealing with this kind of errors ?

Should the code be wrapped with a try/catch ?

Claudio
  • 10,614
  • 4
  • 31
  • 71
  • 3
    In your example a unit-test should pick up your error and fail. Wrapping it in try/except won't fix your problem, you should not use such a construct to detect a logic error. An exception is exactly the behavior that you'd want in this case, so you can find and fix the problem. Since Python is dynamically typed you will always run into this problem, but again, unit-tests should pick it up. – Blubber Jun 11 '13 at 08:28
  • Also, this http://stackoverflow.com/questions/1912476/best-place-to-coerce-convert-to-the-right-type-in-python?rq=1 just popped up in the 'Related' sidebar. – Blubber Jun 11 '13 at 08:36
  • I see. So unit-testing is the right way to handle this kind of issues (in this case I think that static-type checks are more reliable). Many thanks. – Claudio Jun 11 '13 at 08:49

1 Answers1

0

This will not give you checks at compile time, but as you suggested using a try/catch, I will assume that runtime checks would also be helpful.

If you use classes, you could hook your own type checks in the __setattr__ method. For example:

import datetime

# ------------------------------------------------------------------------------
# TypedObject
# ------------------------------------------------------------------------------
class TypedObject(object):     
    attr_types = {'id'         : int,
                  'start_time' : datetime.time,
                  'duration'   : float}

    __slots__ = attr_types.keys()

    # --------------------------------------------------------------------------
    # __setattr__
    # --------------------------------------------------------------------------
    def __setattr__(self, name, value):
        if name not in self.__slots__:
            raise AttributeError(
                "'%s' object has no attribute '%s'" 
                % (self.__class__.__name__, name))
        if type(value) is not self.attr_types[name]:
                raise TypeError(
                    "'%s' object attribute '%s' must be of type '%s'" 
                    % (self.__class__.__name__, name, 
                       self.attr_types[name].__name__))
        # call __setattr__ on parent class
        super(MyTypedObject, self).__setattr__(name, value)

That would result in:

>>> my_typed_object            = TypedObject()

>>> my_typed_object.id         = "XYZ"      # ERROR
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 28, in __setattr__
TypeError: 'MyTypedObject' object attribute 'id' must be of type 'int'

>>> my_typed_object.id         = 123        # OK

You could go on and make the TypedObject above more generic, so that your classes could inherit from it.

Another (probably better) solution (pointed out here) could be to use Entought Traits

Community
  • 1
  • 1
E.Z.
  • 6,393
  • 11
  • 42
  • 69