noob question: "TypeError" wrong number of args
Bruno Desthuilliers
bdesth.quelquechose at free.quelquepart.fr
Tue May 2 21:27:12 EDT 2006
Edward Elliott a écrit :
> bruno at modulix wrote:
>
(snip)
>
>>You skipped the interesting part, so I repost it and ask again: how
>>could the following code work without the instance being an explicit
>>parameter of the function to be used as a method ?
>>
>>def someFunc(obj):
>> try:
>> print obj.name
>> except AttributeError:
>> print "obj %s has no name" % obj
>>
>>import types
>>m = MyObj('parrot')
>>m.someMeth = types.MethodType(someFunc, obj, obj.__class__)
>>m.someMeth()
>
>
> I posted the only part that needs modification.
Nope.
> Here it is again with the
> entire segment:
>
> class MyObj(object):
> def __init__(name):
> self.name = name <== interpreter binds name 'self' to object instance.
> compiler adds 'self' to method sig as 1st param.
>
> def someFunc(obj):
> try:
> print obj.name <== 'obj' gets bound to first arg passed. when bound
> as a method, first arg will be object instance.
> when called as func, it will be first actual arg.
> except AttributeError:
> print "obj %s has no name" % obj
>
> import types
> m = MyObj('parrot')
> m.someMeth = types.MethodType(someFunc, obj, obj.__class__) <== binds obj
> to first parameter of someFunc as usual
> m.someMeth()
>
>
>
>>You see, wrapping a function into a method is not done at compile-time,
>>but at runtime. And it can be done manually outside a class statement.
>>In the above example, someFunc() can be used as a plain function.
>
>
> All the parameter information has been preserved.
> Method signatures are
> unchanged from their current form,
> so the interpreter has no trouble
> deducing arguments. You just don't actually declare self yourself.
In this exemple, it was named 'obj', to make clear that there was
nothing special about 'self'. As you can see from the call, I didn't
actually passed the fist param, since the method wrapper takes care of
it... So if we were to implement your proposition (which seems very
unlikely...), the above code *would not work* - we'd get a TypeError
because of the missing argument.
> When
> binding a function to an object as above, the interpreter sees and does
> exactly the same thing as now.
I'm sorry, but you're just plain wrong. *Please* take time to read about
the descriptor protocol and understand Python's object model.
>
>>This
>>wouldn't work with some automagical injection of the instance in the
>>function's local namespace, because you would then have to write
>>"method"'s code diffently from function's code.
>
>
> Maybe this will make it clearer:
>
> Programmer's view Compiler Interpreter's view
> def func (a, b) func (a, b) -> func (a, b) func (a, b)
> def method (a) method (a) -> method (self, a) method (self, a)
>
> IOW the compiler adds 'self' to the front of the parameter list when
> processing a method declaration.
1/ there is *no* 'method declaration' in Python
2/ wrapping functions into methods happens at runtime, *not* at compile
time.
(snip)
>>>And the rest should work fine. When the interpreter sees a method
>>>declaration,
>>
>>The interpreter never sees a 'method declaration', since there is no
>>such thing as a 'method declaration' in Python. The def statement
>>creates a *function* object:
>
>
> Fine, whatever, compiler sees method declaration,
There ain't *nothing* like a 'method declaration' in Python. Zilch,
nada, none, rien... All there is is the def statement that creates a
*function* (and the class statement that creates a class object).
>
>>>Complete non-sequitor, what does this have to do with self?
>>
>>It has to do that the obj.name() syntax doesn't imply a *method* call -
>>it can as well be a plain function call.
>
> Ok I see your point,
Not quite, I'm afraid.
>
>>Also, and FWIW:
>>
>>>>>def moduleFunc():
>>
>>... print self.name
>>...
>>
>>>>>moduleFunc()
>>
>>Traceback (most recent call last):
>>NameError: global name 'self' is not defined
>
>
> Exactly, that was my point in the first place.
I'm afraid we don't understand each other here. This was supposed to
come as an illustration that, if some black magic was to 'inject' the
instance (here named 'self') in the local namespace of a 'method' (the
way you see it), we would loose the possibility to turn a function into
a method. Try to re-read both examples with s/obj/self/ in the first one
and s/self/obj/ in this last one.
Edward, I know I told you so at least three times, but really,
seriously, do *yourself* a favor : take time to read about descriptors
and metaclasses - and if possible to experiment a bit - so you can get a
better understanding of Python's object model. Then I'll be happy to
continue this discussion (.
FWIW, I too found at first that having to explicitely declare the
instance as first param of a 'function-to-be-used-as-a-method' was an
awful wart. And by that time (Python 1.5.2), it actually *was* a wart
IMVHO - just like the whole 'old-style-class' stuff should I say. But
since 'type-unification' and new-style-classes, the wart has turned into
a feature, even if this only become obvious once you get a good enough
understanding of how the whole damn thing works.
Following it's overall design philosophy, Python exposes (and so let you
take control of) almost any detail of the object model implementation.
The purpose here is to make simple things simple *and* complex things
possibles, and the mean is to have a restricted yet consistent set of
mechanisms. It may not be a jewel of pure beauty, but from a practical
POV, it ends up being more powerful than what you'll find in most
main-stream OOPLs - where simple things happens to be not so simple and
complex things sometime almost impossible - and yet much more usable
than some more powerful but somewhat cryptic OOPLs (like Common Lisp -
which is probably the most astonishing language ever) where almost
anything is possible but even the simplest things tend to be complex.
Oh, also - should I mention it here ? - Ruby is another pretty nice and
powerful OOPL, with a more 'pure' object model (at least at first sight
- I have not enough experience with it to know if it holds its
promises). While Python is My Favourite Language(tm), I'm not too much
religious about this, and can well understand that someone's feature is
someone else's wart - thanks the Lord, everyone is different and unique
-, and you may feel better with Ruby.
More information about the Python-list
mailing list