I was trying to think how a decorator @strict_duck_typing could be implemented to solve the issue Bruce Leban described. The more I think about it, the harder I think it is to implement.

I wanted to do something along the lines of:

def parameters_from_signature(function, args, kwargs):
    "Translate a generic function call to the function's parameters by name"
    argnames, varargs, keywords, defaults = inspect.getargspec(function)
    args_and_kwargs = kwargs.copy()
    names_and_args = zip(argnames, args)
    args_and_kwargs.update(names_and_args)
    if varargs is not None:
        args_and_kwargs[varargs] = args[len(argnames):]
    return args_and_kwargs

def strict_duck_typing(function):
    attr_dict = attributes_used_by_function(function)
    
    def verify_and_run(*args, **kwargs):
        called_with = parameters_from_signature(function, args, kwargs)
        
        for parameter, attributes_needed in attr_dict.items():
            for attr in attributes_needed:
                if not hasattr(called_with[parameter], attr):
                    raise TypeError("Parameter '%s' given doesn't have '%s' attribute/method." % (parameter, attr))
        
        function(*args, **kwargs)

Of course the big enchilada is the function 'attributes_used_by_function' which I left out because it has to do some insane things. I was thinking of using ast.parse(inspect.getsource(function)) and then:
  1. stepping into each function call which involves the function parameters, perhaps repeating the ast.parse/inspect.getsource combo.
  2. collecting all the methods and attributes accessed.
  3. getattr/setattr/hasattr need to be simulated or handled
  4. return a dictionary of { parameter_name: attributes_needed_set }
And even after this crazy piece of work there are some limitations ie:
  1. C functions wouldn't be inspected, which is a tragedy, ie len(), iter(), etc have to be especially treated...
  2. dynamically generated attributes and attribute names will always break this decorator.
  3. performance issues
  4. probably more things i didn't think of...

So I like the idea of strict duck typing, but it's gonna take more than one mailing list reply for me to write a POC :)


On Sun, Sep 20, 2009 at 12:56 PM, Masklinn <masklinn@masklinn.net> wrote:
On 20 Sep 2009, at 06:21 , Bruce Leban wrote:
I don't quite understand what you are trying to solve. Here's a related
problem: One of the issues with duck typing is that something might look
sort of like a duck but isn't really and it would be nice to make it easy to
avoid using an object in a "half-baked" manner:

  def playWithDuck(d):
     d.walk()
     d.quack()

if someone calls playWithDuck(dog) then the dog's going to get walked before
trying to make the dog quack fails.

Note that with a structural type system (that of OCaml's objects for instance) this will work, the `playWithDuck` function will be inferred to take any subtype of < walk : unit; duck : unit > (or something like that) (basically, any object with a `walk` and a `quack` method (both returning nothing) will work).


_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
http://mail.python.org/mailman/listinfo/python-ideas