Trouble with metaclass

F

Fernando Rodriguez

Hi,

I'm having trouble with a metaclass suposed to check the method signature of
its classes.

Here's the metaclass:

class MetaChecker(type):
def __new__(cls, name, bases, attribs):
for name, value in attribs.iteritems():
if inspect.ismethod(value):
if not isSingleArg(value):
raise "%s is not a thunk method!"%name
return type.__new__(cls, name, bases, attribs)


def isSingleArg(fn):

args = inspect.getargspec(fn)[0]
if len(args) == 1:
return 1
else:
return None


And here's a class with this metaclass:

class Preconditions (object):

__metaclass__ = MetaChecker



If I define a descendant of Preprocesor with a method with 2 arguments, I
don't get any error:
class P (Preprocessor):
def f(self, x):
return x


What am I doing wrong? O:)
 
A

anton muhin

Fernando said:
Hi,

I'm having trouble with a metaclass suposed to check the method signature of
its classes.

Here's the metaclass:

class MetaChecker(type):
def __new__(cls, name, bases, attribs):
for name, value in attribs.iteritems():
if inspect.ismethod(value):
if not isSingleArg(value):
raise "%s is not a thunk method!"%name
return type.__new__(cls, name, bases, attribs)


def isSingleArg(fn):

args = inspect.getargspec(fn)[0]
if len(args) == 1:
return 1
else:
return None


And here's a class with this metaclass:

class Preconditions (object):

__metaclass__ = MetaChecker



If I define a descendant of Preprocesor with a method with 2 arguments, I
don't get any error:
class P (Preprocessor):
def f(self, x):
return x


What am I doing wrong? O:)

The problem seems to be with ismethod function. Cf.:

import inspect

class MetaFoo(type):
def __new__(cls, name, bases, attribs):
for name, value in attribs.iteritems():
if inspect.isfunction(value):
print '%s(%s)' % (name, ',
'.join(inspect.getargspec(value)[0])) // Sorry, it's wrapped :(

return type.__new__(cls, name, bases, attribs)

class Base(object):
__metaclass__ = MetaFoo

class Foo(Base):
def method0(self): pass
def method1(self, x): pass
def method2(self, x, y): pass

And compare:

class Foo(object):
def method(self): pass
print 'inside', inspect.ismethod(method)
print 'inside', type(method)

print 'outside', inspect.ismethod(Foo.method)
print 'outside', type(Foo.method)

Python2.3 prints:
inside False
inside <type 'function'>
outside True
outside <type 'instancemethod'>


regards,
anton.
 
A

Alex Martelli

anton said:
Fernando Rodriguez wrote: ... ...
The problem seems to be with ismethod function. Cf.:

Right, or, more precisely, there is no problem with ismethod -- it
correctly reports that the values in the attribs dictionary are not
method objects (they're function objects).

Summarizing and simplifying only a little bit...:

1. The def statement always and exclusively creates a function object.

2. A function object is also a descriptor: when you call f.__get__(x),
you get back a method object with im_func == f and im_self == x.

3. The attribute lookup process calls x.__get__(self) on any attribute
it may find in the class's dictionary.

But at this point in the execution of the metaclass's __new__, there
is no "class dictionary" yet -- there isn't even a _class_ -- just a
plain dictionary of attributes which will BECOME the class dictionary
once you call type.__new-_ with that dict as the 4th argument.


Alex
 
M

Michele Simionato

Fernando Rodriguez said:
Hi,

I'm having trouble with a metaclass suposed to check the method signature of
its classes.

Here's the metaclass:

class MetaChecker(type):
def __new__(cls, name, bases, attribs):
for name, value in attribs.iteritems():
if inspect.ismethod(value):
if not isSingleArg(value):
raise "%s is not a thunk method!"%name
return type.__new__(cls, name, bases, attribs)


def isSingleArg(fn):

args = inspect.getargspec(fn)[0]
if len(args) == 1:
return 1
else:
return None


And here's a class with this metaclass:

class Preconditions (object):

__metaclass__ = MetaChecker



If I define a descendant of Preprocesor with a method with 2 arguments, I
don't get any error:
class P (Preprocessor):
def f(self, x):
return x


What am I doing wrong? O:)

The metaclass is right and actually the names you are using (Preconditions/
Preprocessors) suggest to me that you are using the right tool for the job;
the only problem is that you must use 'inspect.isfunction' and not
'inspect.ismethod', because of the methods <=> functions mismatch I am
sure you know everything about ;) If not, please feel free to ask.

Also, I would use

return super(mcl,MetaChecker).__new__(mcl,name,bases,attribs)

instead of type.__new__, anticipating the need for multiple inheritance
of metaclasses.


Michele
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top