Another try at Python's selfishness

Steven D'Aprano steve at REMOVETHIScyber.com.au
Fri Feb 3 06:57:36 EST 2006


On Fri, 03 Feb 2006 03:23:00 -0800, n.estner wrote:

>> That usage (self is second parameter to B.test) is bound
>> to cause trouble in general, but in this case doesn't have
>> any effect I can see.  The function call "test" would be
>> resolved from its first parameter, instance of A, and that
>> function would return 1.  One of us is missing something
>> here, could be me.
> 
> Probably my example wasn't clear, let's try another:
> 
>   class A:
>     def test(a, **kwargs): return 1
>   class B:
>     def test(b, **kwargs): return 2
>   test(a=A(), b=B())
> 
> "self" isn't a keyword, so nothing should forbid this code. What is the
> interpreter to do if it stumbles across this "test" call? 



You could try running it to see:

>>> class A:
...     def test(a, **kwargs): return 1
...
>>> class B:
...     def test(b, **kwargs): return 2
...
>>> test(a=A(), b=B())
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'test' is not defined


Oops! You have defined a name "test" in two namespaces, the class A and
the class B, but there is no name "test" in the global namespace you are
trying to run it in.

Since namespaces are critical to Python, your test code is a problem that
just cannot happen in Python. It is a non-issue. Python will not get
confused between the two definitions of test.



> I mean,
> named-argument lookup is a tricky thing even if you do know what
> function you're calling. If this would depend on one of the parameters,
> I think it would become completely unintelligible. (you can think of
> more complex examples yourself)
> 
>> That's exactly the problem, it doesn't read from left to right,
>> because we swap back and forth between function(parameter and
>> parameter.function notation.
> 
> That's because they're doing two different things: object.method() does
> an attribute lookup, while function(parameter) looks for the function
> in the current scope.

No, function(parameter) does not look for a function. It looks for any
object at all, and then tries to call it.

Both calls do almost the same thing. object.method() looks up the name
"method" in the object namespace, function(parameter) looks up the name
"function" in the current namespace. Neither "method" nor "function" must
be methods or functions, although if they are not callable objects,
calling them will raise an exception. But regardless of what sort of
objects they are, the look up proceeds in the same fashion.

Unless you understand namespaces, you don't understand Python, and any
criticism is likely to be due to misunderstanding.


As near as I can tell, your original complaint might be solved simply: it
seems to me that you are concerned about that extraneous "self" parameter
for methods that don't need it:

class Foo:
    def bar(self, a,b):
        return a+b
Foo().bar(1,2) => 3

If bar doesn't need the instance or class Foo, perhaps it would be better
off as an ordinary function rather than bound to a class.

But if bar does need to be a method, perhaps you want something like this:


# for Python 2.2 and up
class Foo:
    def bar(a,b):
        return a+b
    bar = staticmethod(bar)

# for Python 2.4 and up
class Foo:
    @staticmethod
    def bar(a,b):
        return a+b

Foo().bar(1,2) works exactly the same as before, but your definition of
bar doesn't need that extraneous "self" parameter.


-- 
Steven.




More information about the Python-list mailing list