@decorator syntax is sugar, but for what exactly?

Mark Bottjer mark_bottjer at hotmail.com
Mon Aug 9 00:41:09 CEST 2004


Avner Ben wrote:
 > So, if the problem is to rid class definitions of bizarre function
 > calls, stuck in the middle of nowhere, that actually add to the
 > structure of the class (and which other OO languages solve by
 > legitimate syntax), I am dissapointed to observe that functuion
 > decorators do not do a complete job after all.

While true, I find this less of a disappointment than you. There are two 
large differences between class/staticmethods and properties: methods 
act like functions, while properties act like variables; and properties 
have multiple associated code blocks (the getter and setter), while 
methods have only one. @decorator as designed applies only to functions, 
and is simply inappropriate for properties. Disappointing, perhaps, but 
not surprising--variables and functions *are* fundamentally different.

 > Talking about properties, I like the C# way of defining them, which
 > is straightforward and readable. The property begins like a method,
 > but has no argument list and includes a getter function with no
 > arguments and a setter function with one argument. Adapted to Python,
 >  it would look something like:
 >
 > class hasProperty:
 >     def __init__(self,aProperty='')
 >         self.aProperty = aProperty
 >     def AProperty:
 >         def get(self):
 >             return self.aProperty
 >         def set(self,value):
 >             self.aProperty = value
 > obj = hasProperty()
 > obj.AProperty = 'test'
 > print obj.AProperty

I, personally, don't like the idea of overloading def in this way. To 
me, 'def' defines something that looks and acts like a function, just 
like 'class' defines something that looks and acts like a class, or 
'while' defines something which looks and acts like a loop. AProperty is 
does not act like a function, so using def would be misleading.

I agree, though, that the best way to handle properties is though some 
sort of extended syntax. After all, we already have *a* way of doing it, 
we just don't like how it looks. To fix this, we need to compress the 
various pieces (name, storage, getter, setter, etc.) into a single 
declarative construct. (In fact, this is a large part of my problem with 
the proposed @ syntax: it isn't part of the function it modifies, but 
rather some sort of odd prefix. OTOH, the prefix notation would work 
with variables as well as functions, which is not possible with an infix 
notation: @global; x=10. Whether or not this is actually of any benefit 
is left as an exercise for the reader.)

I've thought for a while now that Python is skirting a breakthrough in 
how it treats statements. Python took a step in the right direction with 
generalizing iteration via generators, and I see utility in generalizing 
the idea of statements as well. In particular, what I'd like to see is 
the ability to define new *types* of statement.

Consider again the classmethod, staticmethod, and property. If these 
were defined as extended statements, we could code them more naturally:

   class C:
     c = 'Hi there!'

     class_def cm( c, a, b):   # class method
       return 'C(%r).cm( %r, %r) -> %r' % (id(c), a, b, c.c)

     static_def sm( a, b):       # static method
       return 'C.sm( %r, %r) -> %r' % (a, b, a % b)

     def im( s, a, b):        # instance method
       return 'C(%r).im( %r, %r) -> %r' % (id(s), a, b, (a % b) * self.a)

     def __init__( s, a):     # constructor
       s.a.__init__( a)

     property a:
       def __init__( s, v):
         __set__( s, v)
       def __get__( s):
         print 'C(%r).a -> %r' % (s, s.__a)
         return a
       def __set__( s, v):
         print 'C(%r).a <- %r' % (s, v)
         a = v

   >>> o = C( 3.1415)
   C(<C instance at 0x98765432>).a <- 3.1415
   >>> o.cm( 2, 3)
   C(<class C at 0x12345678>).cm( 2, 3) -> 'Hi there!'
   >>> o.sm( 4, 5)
   C.sm( 4, 5) -> 4
   >>> o.im( 6, 7)
   C(<C instance at 0x98765432>).a -> 3.1415
   C.im( 6, 7) -> 18.849
   >>> o.a
   C(<C instance at 0x98765432>).a -> 3.1415
   3.1415

In the above, 'class' is as we know them. 'class_def' and 'static_def' 
are statements similar to 'def', but define a class method or static 
method, respectively. Finally, 'property' is a statement which defines a 
new property, and takes a code block expected to contain functions with 
predefined names. Each of these could be implemented natively, or the 
way we would do it manually today.

Taking this to the extreme, all existing statement types (class, def, 
print, del, etc.) could be recast as these generalized statements. We 
could even allow subclassing of existing statements to modify their 
behavior (for example, class_def subclassing def to make the new 
function a class method). Strong Kung-Fu indeed. Scary, but strong.

Obviously, creating new control constructs is not something we'd want to
do every day, as it can be a great way to obfuscate code beyond all hope
of understanding--but the same is true of meta-classes. Just because it 
*could* be abused doesn't mean that it would be.

On the flip side, this doesn't address some of the more creative uses of 
decorators that people have been proposing. A new statement type, like 
class_def, effectively applies a fixed set of decorators (in the case of 
class_def, it applies only classmethod); if we want more variety, we 
still need decorators. They are independent ideas, even though they can 
overlap a bit.

I have absolutely no idea as to *how* any of this would be accomplished, 
mind you, but it would be *terribly* nifty.

   -- Mark



More information about the Python-list mailing list