Hi I found two bugs in example 4 of the PEP 318 [1]. People on #python pointed me to this list. So here is my report. Additionally I appended an afaics correct implementation for this task.
[1] http://www.python.org/dev/peps/pep-0318/ Bug 1) The decorator "accepts" gets the function which is returned by the decorator "returns". This is the function "new_f" which is defined differently from the function "func". Because the first has an argument count of zero, the assertion on line 3 is wrong. Bug 2) The assertion on line 6 does not work correctly for tuples. If the second argument of "isinstance" is a tuple, the function returns true, if the first argument is an instance of either type of the tuple. Unfortunately the example uses tuples. Here goes my proposal for this decorators. Feel free to do anything you like with it. ---8<--- def checktype(o, t): """check if the type of the object "o" is "t" """ # in case of a tuple descend if isinstance(t, tuple): assert isinstance(o, tuple), str(type(o)) assert len(o) == len(t), "%d %d" % (len(o), len(t)) for (o2, t2) in zip(o, t): checktype(o2, t2) # isinsance(None, None) raises a TypeError. # so we need extra handling for this case elif t == None: assert o == None else: assert isinstance(o, t), "%s %s" % (str(type(o)), str(t)) class accepts(object): def __init__(self, *types): self.types = types def __call__(self, func): self.func = func def check(*args, **kwds): checktype(args, self.types) self.func(*args, **kwds) return check class returns(object): def __init__(self, *types): self.types = types def __call__(self, func): self.func = func def check(*args, **kwds): value = self.func(*args, **kwds) # if the function returns only on object the single object is no tuple # this extra case results in an extra handling here if isinstance(value, tuple): checktype(value, self.types) else: checktype((value,), self.types) return value return check --->8--- To be honest, I didn't understand what the purpose of setting "func_name" is, so I left it out. If its neccessary please feel free to correct me. In contrast to tuples lists and dictionaries are not inspected. The reason is that I don't know how to express: "the function accepts a list of 3 or more integers" or alike. Perhaps somebody has an idea for this. Here are some examples of what is possible: ---8<--- @accepts(int) @returns(int) def foo(a): return a foo(3) @accepts(int, (float, int)) @returns(int, str) def foo(a, b): return (1, "asdf") foo(1, (2.0, 1)) @returns(None) def foo(): pass foo() @accepts(int, int) def foo(a, *args): pass foo(3,3) @accepts(tuple) @returns(list) def foo(a): return list(a) foo((1,1)) --->8--- I wonder, how it can be, that those imho obvious mistakes go into a PEP and stay undetected there for almost 3 years. Perhaps I misunderstood something completly. In this case, please excuse me and ignore my mail. The welcome message to this lists asked for introducing myself. Well, there is nothing special to say about me concerning python. Let's say, I'm just a fan. cu -- Alexander Bernauer _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com