Typechecking Methods

Previously...

In our last lesson, we learned how to use Python's built-in list, tuple, dict and set types in your signatures. In this section, we'll go over typecheck's notion of utility classes, which allow you to express a much larger, much more precise signature for your code.

So far, all the examples have used functions to demonstrate the decorators, they can also be employed with methods (of both new- and old-style classes). The only new thing to learn is Self(); observe:

class Foo:
	@accepts(Self(), Number, Number)
	@returns( [float] )
	def foo(self, a, b):
		...
		return list_of_floats

The Self() callable is effectively a placeholder, allowing you to specify a type for the self object. Self() can also be used to insist that other parameters (or return values) be of the same class as the invocant:

class Foo:
	@accepts(Self(), Number, Mapping, Self())
	@returns( [Self()] )
	def foo(self, a, b, c):
		...
		return our_list

This signature insists that c be an instance of the same class as self, and that the function returns a list of instances of this same class.

Note: because of current limitations in the Python language itself, if you want to use Self() in a yields or returns signature, the function/generator/method must have a accepts signature that uses Self().

The Class() Class

Let's say you have a situation like this:

class ClassA:
	@accepts(Self(), ClassB)
	def foo(self, b):
		...
		
class ClassB:
	@accepts(Self(), ClassA)
	def bar(self, a):
		...

See the problem? You can't use ClassB in the signature for ClassA.foo because it hasn't been declared yet. Sure, you could reverse the order of the class declarations, but then you'd have the same problem with ClassB.bar. The solution: the Class() utility class.

ClassB = Class("ClassB")
				
class ClassA:
	@accepts(Self(), ClassB)
	def foo(self, b):
		...
		
class ClassB:
	@accepts(Self(), ClassA)
	def bar(self, a):
		...

The Class() utility class allows deferring the lookup of the named class until it's actually needed for typechecking. Note the idiom used above: assign the Class() instance to a variable with the same name as the desired class. This is much cleaner than inlining the call to Class().

Next...

In our next lesson, we'll extend what we've learned so far to cover methods of all flavours.

Valid XHTML 1.0 Transitional