PEP: Specialization Syntax

Bengt Richter bokr at oz.net
Sun Aug 7 20:51:22 EDT 2005


On Sun, 07 Aug 2005 16:22:11 -0400, Nicolas Fleury <nidoizo at yahoo.com> wrote:

>Hi everyone, I would to know what do you think of this PEP.  Any comment 
>welcomed (even about English mistakes).
>
>PEP: 	XXX
>Title: 	Specialization Syntax
>Version: 	$Revision: 1.10 $
>Last-Modified: 	$Date: 2003/09/22 04:51:49 $
>Author: 	Nicolas Fleury <nidoizo at gmail.com>
>Status: 	Draft
>Type: 	Standards Track
>Content-Type: 	text/plain
>Created: 	24-Jul-2005
>Python-Version:	2.5
>Post-History: 	
>Abstract
>
>     This PEP proposes a syntax in Python to do what is called in
>     this document "specialization".  It contains more than one
>     proposal:
>     - Extend square brackets syntax to allow a full call syntax,
>       using a __specialize__ method, similarly to the __call__
>       method.
>     - Extend function definition syntax to allow specialization
>       of functions.
>     - Parameterized types.
>
>
>Motivation
>
>     In his controversial blog entry "Adding Optional Typing to
>     Python -- Part II" [1], Guido Van Rossum introduced the idea
>     of "parameterized types" in Python.  The proposition was to
>     use [square brackets] rather than <pointy ones> to allow
>     prototyping with __getitem__ method.  However, the __getitem__
>     method is not flexible enough.  It doesn't support keyword
>     arguments and using multiple and default arguments can be pain,
>     since the only argument received would be a tuple.  Calling
>     can also be error-prone if a tuple can be allowed as a first
>     argument.  This PEP proposes to enhance square brackets syntax
>     to allow full-call syntax as with parenthesis.
>
>     Note that Guido dropped the idea, for now, of parameterized
>     types in a following blog entry [2].  This PEP introduces
>     parameterized types only as a last step, and focus more on
>     having a syntax to prototype them.  This PEP can also serve
>     as a place to discuss to feature of specialization independently.
>
>     The term "specialization" is used in that document because
>     "parameterized functions" would sound like an already available
>     feature.  As Guido pointed out [1], "generic" is neither a good
>     term.  Specialization is a term in that case borrowed from C++.
>     The term alone is not perfect, since it refers to the action of
>     passing arguments to a "parameterized type" (or function) to
>     make it usable and a term must still be found to describe the
>     "unspecialized" type or function.
>
>     Another motivation to this PEP is the frequent usage in Python
>     of functions to create functions.  This pattern is often used
>     to create callback functions and decorators, to only name these.
>     However, the fact that both the creation and the use is using
>     parenthesis can be confusing.  Also, a programmer ends up naming
>     two functions, when only the creating one is called by name and
>     the created one is doing the job.  Some programmers ends up
>     naming the creating function with the name they would want to
>     give to the created function, confusing even more the code using
>     it.  To fix this situation, this PEP proposes a syntax for
>     function specialization.
>
>
>__specialize__ Special Member Function.
By "Member Function" do you mean anything different from "method"?

>
>     The first element of this proposal is the addition of the
>     __specialize__ special member function.  The __specialize__
>     function can have the same signatures as __call__.  When
Any function can have any legal signature, so I'm not sure what you are saying.

>     defined, the definition of __getitem__ has no effect, and
>     __specialize__ will be called instead.
What about subclassing and overriding __getitem__ ?

>
>     The language grammar is extended to allow keyword arguments
>     and no arguments.  For example:
>
>         class MyObject(object):
>             def __specialize__(self, a=4, b=6, *args, **kwargs):
>                 pass
here you can currently write
              __getitem__ = __specialize__
although you have to remember that obj[:] and related slicing expressions
become legal and that obj[] does not, without a language sysntax change.
>
>         obj = MyObject()
>         obj[b=7, a=8, c=10]
>         obj[]
>
>     Note that when __specialize__ is defined, __setitem__,
>     __getslice__ and __setslice__ are still used as before.
>
>
>The specializer Decorator
>
>     To explain the syntaxes proposed in this PEP, the following
>     decorator is used:
>
>         class Specializer:
>             def __init__(self, callableObj):
>                 self.callableObj
                                   ^^?? = callableObj ?
>                 self.__name__ = callableObj.__name__
>             def __specialize__(self, *args, **kwargs):
>                 self.callableObj(*args, **kwargs)
>
>         def specializer(callableObj):
>             return Specializer(callableObj)
>
>     It takes a callable and make it callable with square brackets
>     instead.
Well, it wraps it, but the thing itself is still called as before from the wrapper,
so "it" itself is not "callable" with square brackets ;-)

>
>
>Function Specialization
>
>     A common pattern in Python is to use a function to create
>     another function:
>
>         def makeGetMemberFunc(memberName):
>             def getMember(object):
>                 return getattr(object, memberName)
>             return getMember
>
>         foo(makeGetMemberFunc('xyz'))

Either closures like the above or bound methods work for this,
so you just want more concise spelling?

>
>     The second element of this proposal is to add a syntax so
>     that the previous example can be replaced by:
>
>         def getMember[memberName](object):
>             return getattr(object, memberName)
>
>         foo(getMember['xyz'])
>
>     which is equivalent to:
>
>         @specializer
>         def getMember(memberName):
>             def getMember(object):
>                 return getattr(object, memberName)
>             return getMember
>
>         foo(getMember['xyz'])

Have you looked at currying? E.g.,
    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52549

Also, I made a byte-hacking decorator that is able to inject local presets
into a function itself (hence without wrapping overhead when used) or to curry
in another variation of the decorator. E.g.,

 >>> from ut.presets import presets, curry
 >>> @curry(memberName='xyz')
 ... def getMember(obj, memberName):
 ...     return getattr(obj, memberName)
 ...
 >>> o = type('',(),{})()
 >>> o.xyz = 'This is object o attribute xyz'
 >>> getMember(o)
 'This is object o attribute xyz'
 >>> import dis
 >>> dis.dis(getMember)
   1           0 LOAD_CONST               1 ('xyz')
               3 STORE_FAST               1 (memberName)

   3           6 LOAD_GLOBAL              0 (getattr)
               9 LOAD_FAST                0 (obj)
              12 LOAD_FAST                1 (memberName)
              15 CALL_FUNCTION            2
              18 RETURN_VALUE
 >>> getMember.func_code.co_argcount
 1

Or the presets decorator can make the preset available without
having been a part of the original signature at all:

 >>> @presets(attname='xyz')
 ... def foo(obj): return getattr(obj, attname)
 ...
 >>> foo(o)
 'This is object o attribute xyz'
 >>> dis.dis(foo)
   1           0 LOAD_CONST               1 ('xyz')
               3 STORE_FAST               1 (attname)

   3           6 LOAD_GLOBAL              0 (getattr)
               9 LOAD_FAST                0 (obj)
              12 LOAD_FAST                1 (attname)
              15 CALL_FUNCTION            2
              18 RETURN_VALUE

As mentioned, these are byte code hacks. So they are pretty
fragile, version-portability-wise.

>
>
>Class Specialization
>
>     The last element of this proposal is to add a syntax to pass
>     arguments to class creation:
>
>         class List[ElementType=object](list):
>             ...
>
>     This would be the equivalent to:
>
>         @specializer
>         def List(ElementType=object):
>             class List(list):
>                 ...
>             return List
>
>     Note that the additional syntax is inserted before the
>     inheritance, different than what was initially proposed [1].
>     The reason is that inheritance can need the specialization
>     arguments, and it is more intuitive to use an argument
>     after its introduction:
>
>         class MyList[ElementType=object](List[ElementType]):
>             ...
>
>
Before I'd want to extend class syntax this way, I think I'd want to
explore some other aspects of class syntax as well, with more (and
more persuasive) use cases in view. Also more thought to what is done
when and whether the issue is to supply information into existing control
contexts or to modify control flow as well, to extend possibilities for
customized processing.


>Backward Compatibility
>
>     The three propositions are backward compatible.
>
>
>Open Issues
>
>     Instead of adding a __specialize__ method, the __getitem__
When you say "the" __getitem__ method, what do you mean? AFAIK the
method itself is an unrestricted function. It just happens that
binding it as a class attribute __getitem__ makes it get called
from code with square bracket access spellings. I think that's where
your changes to allow "additional signatures" would have to go. I.e.,
in generation of code from the "calling" syntax. To illustrate:

 >>> class C(object):
 ...     def __getitem__(self, *args, **kwargs):
 ...         return self, args, kwargs
 ...
 >>> c=C()
 >>> c[1]
 (<__main__.C object at 0x02EF498C>, (1,), {})
 >>> c[1,2]
 (<__main__.C object at 0x02EF498C>, ((1, 2),), {})
 >>> c[:]
 (<__main__.C object at 0x02EF498C>, (slice(None, None, None),), {})
 >>> c[kw='key word arg']
   File "<stdin>", line 1
     c[kw='key word arg']
         ^
 SyntaxError: invalid syntax

But here the problem is not in the __getitem__ method:

 >>> c.__getitem__(kw='key word arg')
 (<__main__.C object at 0x02EF498C>, (), {'kw': 'key word arg'})

It's just that square bracket expression trailer syntax does not
allow the same arg list syntax as parenthesis calling trailer syntax.

>     method could be changed to allow additional signatures:
>
>         def __getitem__(self, *args, **kwargs): ...
>
>     Should other operators that square brackets be used for
>     specialization?
Didn't quite parse that ;-) You mean list comprehensions? Or ??
>
>
>References
>
>     [1] Adding Optional Static Typing to Python -- Part II,
>         Guido van Rossum
>         http://www.artima.com/weblogs/viewpost.jsp?thread=86641
>
>     [2] Optional Static Typing -- Stop the Flames!, Guido van Rossum
>         http://www.artima.com/weblogs/viewpost.jsp?thread=87182
>
>
>Copyright
>
>     This document has been placed in the public domain.
>

Regards,
Bengt Richter



More information about the Python-list mailing list