[Python-Dev] Draft proposal: Implicit self in Python 3.0

Alexander Kozlovsky alexander.kozlovsky at gmail.com
Fri Jan 6 21:26:55 CET 2006


Hello!

Ian Bicking wrote:
> (As an aside directed at the original PEP, I think discussion of leaving
> self out of expressions, e.g., ".x" for "self.x", should be separate 
> from the rest of this PEP).

Yes, I'm fully agree.


Nick Coghlan wrote:
> The main concern I have is with the answer to the question "How many
> positional arguments does the function have if I retrieve it from the class, 
> rather than from an instance?" (this is the common concern for almost all 
> proposals to remove the explicit self and class_ slots).

In this case, the function always (!!!) has fixed number of
positional arguments equal to number of positional parameters
inside the function definition:

  >>> def func(a, b):
  ...     print class, self, a, b
  ...
  >>> class Foo:
  ...     bar = func
  ...
  >>> instance = Foo()
  >>> func(1, 2)          # there are 2 arguments
  None None 1 2           #   <- class and self both equal to None
  >>> Foo.bar(1, 2)       # 2 arguments again!!
  <class Foo> None 1 2    #   <- self is equal to None
  >>> instance.bar(1, 2)  # 2 arguments always!!!
  <class Foo> <Foo object at 0x016434F0> 1 2

  
Nick Coghlan wrote:
> To sum the proposal up in my own words:
>    Eliminate the need for explicit class and self slots in class
> and instance methods by implicitly providing those slots on all
> functions.

Yes, I think, it is what I mean.

With my proposal, 'self' is no longer the first explicit or implicit
positional argument (!), instead, it is 'pseudo-argument', the value
of which is equal to function's 'im_self' attribute. Any function
contains two special read-only attributes: 'im_class' and 'im_self',
and values of this attributes are accessible inside function body
as values of 'class' and 'self' pseudo-arguments.

Any function has this attributes, for ordinary function their values
are set to 'None'. Example:

  >>> # Python 3.0
  >>> def f(): return class, self
  >>> f()
  (None, None)

There is new built-in function:

    bind(old_function, self_, class_=None) -> new_function
  
The result is the new function with the same code object which the
old function had, but with different im_class and im_self attributes
values.

- If both self_ and class_ arguments are None, then 'im_class' and
  'im_self' attributes of new function is set to equal to None.

- If self_ is not None, then class_ must be None or self_.__class__.
  'im_self' attribute of new function is set to self_, and im_class
  attribute is set to self_.__class__

- If self_ is None but class_ is not None, then 'im_self' attribute
  is set to None, and 'im_class' attribute is set to class_

Consider this expression (extraction of a method from a class):

   x = Foo.bar

This expression is equivalent of:

   x = bind(Foo.__dict__["bar"], None, Foo)

After this, x.im_class is Foo and x.im_self is None
The type.__getattribute__ contains implementation of this
   
Consider next expression (extraction of a method from an instance):

   y = instance.bar

This expression is equivalent of:

   y = bind(instance.__class__.__dict__["bar"], instance)

After this, y.im_class is instance.__class__ and y.im_self is instance.
The object.__getattribute__ is responsible for this

Ian Bicking wrote:
> Well... it becomes more complex for decorators, I guess:
> 
>    def printargs(func):
>        def replacement(*args, **kw):
>            print args, kw
>            return func(*args, **kw)
>        return replacement
>    class Foo:
>        @printargs
>        def null(a): pass
> 
> What is printargs going to print?  Will it even work?  I'd guess you'd 
> have to do:
> 
>    def printargs(func):
>        def replacement(*args, **kw):
>            print args, kw
>            return bind(func, self)(*args, **kw)
>        return replacement

I think, it should be:

    def printargs(func):
        def replacement(*args, **kw):
            print args, kw
            return bind(func, self, class)(*args, **kw)
        return replacement

Yep, the code in decorators will be more complicated than it is today.
I did not get it before...

> I guess it depends on what bind(func, self) does outside of
> a method invocation.  I think self should be undefined in that case.

'self' will be None in that case. Any function has 'self' pseudo-argument,
but in a plain function (not a method) 'self' and 'class' both equal
to None.



-- 
Best regards,
 Alexander                mailto:alexander.kozlovsky at gmail.com



More information about the Python-Dev mailing list