Working with method-wrapper objects

Dr. Peer Griebel griebel at konzept-is.de
Tue May 3 06:41:45 EDT 2005


Bengt Richter wrote:
> On Thu, 28 Apr 2005 11:33:04 +0200, "Dr. Peer Griebel" <griebel at konzept-is.de> wrote:
> 
> 
>>Peer Dr. Griebel wrote:
> 
> [..]
> 
>>>Why has [].__str__ a different type than object.__str__?
>>>Why is object.__str__ a routine while object().__str__ not?
> 
> Why wouldn't you expect different types? Those are different expressions.

Yes but for old style classes it's different (seems easier). For me the 
difference between bound and unbound methods are quite obvious. And I 
can easily work with these kind ob instances. (E.g. I know about im_self).

> If they were types and instances of your own making,
> like class Foo(object) and Foo(), wouldn't you expect
> a difference between Foo.method and Foo().method ?

Yes I expect differences in the implementation. But I did not expect 
these large difficulties (of mine) to work with new style classes. And 
as you have shown in your mail (thanks about it!) it is relatively tricky.

[..]

>>>And one again my question: Can I extract some more information about a
>>>methed-wrapper object. E.g. can I somehow determine the arg spec?
> 
> I believe it is a descriptor, and as such has at least a __get__ method,
> and to be callable itself, a __call__ method. I think the latter being a method wrapper
> probably effectively does wrapper.__get__(obj, type(obj))(*args, **kw)
> when you do wrapper.__call__(obj, *args, **kw)), which you do when you
> do wrapper(obj, your_args, your_keywords)
> 
> E.g., taking an ordinary class may show it more clearly:
> 
>  >>> class Foo(object):
>  ...    def m(self, *args, **kw): return self, args, kw
>  ...
>  >>> foo = Foo()
>  >>> type(foo).mro()
>  [<class '__main__.Foo'>, <type 'object'>]
>  >>> type(foo).mro()[0].__dict__
>  <dictproxy object at 0x02E8147C>
>  >>> type(foo).mro()[0].__dict__['m']
>  <function m at 0x02EE8D4C>
>  >>> type(foo).mro()[0].__dict__['m'].__get__
>  <method-wrapper object at 0x02EF1A6C>
>  >>> type(foo).mro()[0].__dict__['m'].__get__(foo, type(foo))
>  <bound method Foo.m of <__main__.Foo object at 0x02EF1BAC>>
>  >>> type(foo).mro()[0].__dict__['m'].__get__(foo, type(foo)).__call__
>  <method-wrapper object at 0x02EF1CAC>
>  >>> type(foo).mro()[0].__dict__['m'].__get__(foo, type(foo)).__call__('arg', k='keyword')
>  (<__main__.Foo object at 0x02EF1BAC>, ('arg',), {'k': 'keyword'})
> 
> Now you can try the same with inherited methods like __str__ that are built-in, e.g., substitute
> foo = [1, 2, 'this is a particular list instance'] and note similarities, if you realize what is a
> dscriptor and follow the same kind of logic to the final method call via __call__
> 
>  >>> foo = [1, 2, 'this is a particular list instance']
>  >>> type(foo).mro()
>  [<type 'list'>, <type 'object'>]
>  >>> type(foo).mro()[0].__dict__
>  <dictproxy object at 0x02E813EC>
>  >>> type(foo).mro()[0].__dict__['__str__']
>  Traceback (most recent call last):
>    File "<stdin>", line 1, in ?
>  KeyError: '__str__'
>  >>> type(foo).mro()[1].__dict__['__str__']
>  <slot wrapper '__str__' of 'object' objects>
>  >>> type(foo).mro()[1].__dict__['__str__'].__get__
>  <method-wrapper object at 0x02EF1AEC>
>  >>> type(foo).mro()[1].__dict__['__str__'].__get__(foo, type(foo))
>  <method-wrapper object at 0x02EF1BAC>
>  >>> type(foo).mro()[1].__dict__['__str__'].__get__(foo, type(foo)).__call__
>  <method-wrapper object at 0x02EF1D2C>
>  >>> type(foo).mro()[1].__dict__['__str__'].__get__(foo, type(foo)).__call__()
>  "[1, 2, 'this is a particular list instance']"

Sorry, I think you got me wrong: I would like to get information about 
the argspec itself as it is possible by using module inspect (for old 
style classes).

 >>> import inspect
 >>> def f(p, *q, **r): pass
...
 >>> inspect.getargspec(f)
(['p'], 'q', 'r', None)
 >>> inspect.getargspec([].__str__)
Traceback (most recent call last):
   File "<stdin>", line 1, in ?
   File "/usr/lib/python2.4/inspect.py", line 666, in getargspec
     raise TypeError('arg is not a Python function')
TypeError: arg is not a Python function

>>Isn't there anybody who has something to say about the issue?
>>
> 
> Ultimately you have to go into the code of ceval.c and object.c and typeobject.c
> etc to see what is really happening.

So there is no real (textual) documentation about it?

>>I think it's not only a problem with inspect. It is aproblem about old 
>>style classes vs. new style classes. It seems that the support for new 
>>style classes is not complete (yet).
>>
>>Some more investigation shows that also the module "types" is not 
>>universally usable. E.g. InstanceType is only usabel for instances of 
>>old classes. How do I test for instances of new classes?
> 
> 
> Not certain, but hasattr(inst, '__new__') might be close. And mnemonic ;-)
> 
> Regards,
> Bengt Richter

Are there any plans to enhace types.py and inspect.py to offer more 
support for new style classes?

As you can see, my knowledge is (not yet) good enough to work it out myself.

Thanks,
   Peer




More information about the Python-list mailing list