noob question: "TypeError" wrong number of args
nobody at 127.0.0.1
Tue May 2 21:53:58 CEST 2006
bruno at modulix wrote:
> It is to be taken literally. Either you talk about how Python
> effectively works or the whole discussion is useless.
I started talking about the code-level view (programmer's perspective) so
shorthand was fine. Now that we've moved on to interpreter/compiler-level
stuff, I agree that more precision is warranted.
> 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):
> 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__)
I posted the only part that needs modification. Here it is again with the
self.name = name <== interpreter binds name 'self' to object instance.
compiler adds 'self' to method sig as 1st param.
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.
print "obj %s has no name" % obj
m = MyObj('parrot')
m.someMeth = types.MethodType(someFunc, obj, obj.__class__) <== binds obj
to first parameter of someFunc as usual
> 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. When
binding a function to an object as above, the interpreter sees and does
exactly the same thing as now.
> 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. Interpreter sees the same signature as
now, only programmer doesn't have to write 'self' anymore.
>> And the rest should work fine. When the interpreter sees a method
> 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, interpreter sees function
object. The point is, the interpreter sees the same thing it does now.
>> 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, but it doesn't matter because the interpreter sees the
same function object as before.
This confusion is partly (mostly? ;) my fault. I haven't been
distinguishing precisely between the interpreter and the compiler because
usually with Python it doesn't matter (in practice). This is clearly one
place it does. In the words of Douglas Adams: We apologize for the
> Also, and FWIW:
>>>> def moduleFunc():
> ... print self.name
> Traceback (most recent call last):
> NameError: global name 'self' is not defined
Exactly, that was my point in the first place.
More information about the Python-list