[Tutor] Metaclass programming

Kent Johnson kent37 at tds.net
Tue Sep 4 14:02:59 CEST 2007


Orest Kozyar wrote:
> I have the following code:
> 
> class meta(type):
> 
> 	def __call__(cls, *args, **kwargs):
> 		argnames = inspect.getargspec(cls.__init__)[0]
> 		for i, value in enumerate(args):
> 			kwargs[argnames[i]] = value

This could be written
   kwargs.update(zip(argnames, args))

> 		return type.__call__(cls, kwargs)

You are passing kwargs as a positional argument to __call__(); i.e. 
passing the dict as an ordinary parameter. To use kwargs as the keyword 
dict for the call, use the syntax
   type.__call__(cls, **kwargs)

> class test(object):
> 
> 	__metaclass__ = meta
> 
> 	def __init__(self, x, y, **kwargs):
> 		pass
> 
> However, inspect.getargspec(cls.__init__) appears to return only the
> arguments of the meta __init__ rather than the test __init__.  Is there any
> way I can get access to the test __init__ function from the metaclass?

It works for me:

import inspect

class meta(type):
	def __call__(cls, *args, **kwargs):
		print inspect.getargspec(cls.__init__)
		return type.__call__(cls, *args, **kwargs)

class test(object):
	__metaclass__ = meta

	def __init__(self, x, y, **kwargs):
		pass

test(1, 2)

prints (['self', 'x', 'y'], None, 'kwargs', None)


I think the problem is elsewhere in your code. When I use
   return type.__call__(cls, kwargs)

I get
   TypeError: __init__() takes exactly 3 arguments (2 given)

because test.__init__() is still expecting the two required positional 
arguments.

Why are you doing this?

Kent


More information about the Tutor mailing list