Re: RELEASED Python 2.4, alpha 2

Discussion in 'Python' started by Anthony Baxter, Aug 5, 2004.

  1. > This is a bad joke after all the strong perplexities showed about its
    > decorators solution.
    > I vote against the "@decorator before function" solution.


    Please feel free to actually provide reasons for not liking @decorators.

    Also - if you think you don't like it - please _try_ _it_ _out_ first.

    Anthony
    Anthony Baxter, Aug 5, 2004
    #1
    1. Advertising

  2. Anthony Baxter

    Peter Hansen Guest

    Anthony Baxter wrote:

    >>This is a bad joke after all the strong perplexities showed about its
    >>decorators solution.
    >>I vote against the "@decorator before function" solution.

    >
    > Please feel free to actually provide reasons for not liking @decorators.
    >
    > Also - if you think you don't like it - please _try_ _it_ _out_ first.


    Actually, I think many people *are* trying it out right now...
    by reading the posts in this forum.

    Python is not supposed to be a write-only language, as are some
    other P languages that tend to use lots of punctuation for arbitrary
    purposes (as surely no one has forgotten).

    Python is supposed to be an *eminently readable* language. Those
    of us objecting on the grounds of things like "ugliness" are actually
    *reading* the examples and sample code that are being posted, and
    are finding them *highly unreadable*. This is a valid reaction, and
    since code is more often read than written (as again I don't need
    to remind anyone), the readability of a feature should weigh much
    more heavily than how easy it is to use after you try it out for
    yourself. IMHO.

    Yes, of course after using them for a while they will become more
    readable, but there are people who have learned to speak Klingon as
    well -- and that doesn't change the fact that Klingon is deliberately
    very difficult to learn and awkward.

    Furthermore, a number of people seem to be claiming that decorators
    will be rarely used, so the @ syntax shouldn't be considered a problem.
    They are getting it exactly backwards! If decorators will be rarely
    used, then make sure the syntax is more readable than not, and even if
    it's a tad more cumbersome to write, who will mind? They aren't going
    to be used that often, right?!

    -Peter
    Peter Hansen, Aug 5, 2004
    #2
    1. Advertising

  3. On Thu, 05 Aug 2004 12:18:22 -0400, Peter Hansen <> wrote:
    > Actually, I think many people *are* trying it out right now...
    > by reading the posts in this forum.


    Browsing a few examples in isolation is hardly the same thing as trying it out
    with real live coding.

    I did this, and found my initial "oh yuck" reaction ended up being "actually,
    this isn't too bad".
    Anthony Baxter, Aug 5, 2004
    #3
  4. On Fri, 6 Aug 2004, Anthony Baxter wrote:

    > Please feel free to actually provide reasons for not liking @decorators.


    or [decorators], or what have you:

    What does one do if a decorator raises an exception? If it's something
    necessary to the functioning of the code (say, classmethod or
    staticmethod), then all is as it should be. But what if it's not? What
    if you're using a run-time type checking library, or a code optimizer,
    that may not be installed? In that case you would most likely want to let
    that decoration fail silently. To get around this, you'd either have to
    rewrite that decorator and any above it in the chain as just normal
    decorations, or use some other weird hack.

    Decorators in general are the right solution for the wrong problem (as I
    detailed in another thread). They are being introduced much too
    prematurely, and have not been given time to be able to have been thought
    through well enough. The @ syntax is the result of trying to shoehorn too
    many solutions into one fix.

    They purport to solve the problems of function type declaration
    (class/static), function attributes, runtime type checking, and general
    function mangling, when each of these (save general function mangling)
    already have distinct solutions in nearly every other language. The first
    three problems are currently implemented as hacks in Python that happen to
    fall under the category of "general function mangling". Streamlining the
    hack is not the answer.
    Christopher T King, Aug 5, 2004
    #4
  5. As all people here seem to be bashing on the new syntax, I thought I might
    throw in a little different oppinion... At least for my eye, decorators look
    fine the way they are in 2.4a2.

    Am Donnerstag, 5. August 2004 18:18 schrieb Peter Hansen:
    > Yes, of course after using them for a while they will become more
    > readable, but there are people who have learned to speak Klingon as
    > well -- and that doesn't change the fact that Klingon is deliberately
    > very difficult to learn and awkward.


    I don't think comparing the @ syntax to Klingon is fair to the proposed syntax
    for decorators. Just think of the following:

    class someobject(object):

    @synchronized
    @classmethod
    def x(cls):
    pass

    If I were to translate this to english, I could read it as follows (note the
    order):

    Define a _class someobject_ which has a _synchronized_ _classmethod_ x.

    The @ signs don't disturb my eye, they only make it clear that this method is
    special. All other proposed syntaxes don't have this "shows up right away"
    feeling.

    I know there are problems with formatting tools (python-mode finds the syntax
    as stated difficult to grasp at the moment, listing functions doesn't work
    properly anymore), but I don't think a language is made by it's tools, but
    the tools are made for the language. And so, if the language evolves, it's
    only fair that the tools need to evolve too...

    Anyway, I'm +1 for keeping the syntax as is. It's fine for me.

    Heiko.
    Heiko Wundram, Aug 5, 2004
    #5
  6. On Thu, 5 Aug 2004 12:29:51 -0400, Christopher T King <> wrote:
    > What does one do if a decorator raises an exception?


    def deco(func):
    raise TypeError

    @deco
    def foo():
    print "hello"



    > If it's something
    > necessary to the functioning of the code (say, classmethod or
    > staticmethod), then all is as it should be. But what if it's not? What
    > if you're using a run-time type checking library, or a code optimizer,
    > that may not be installed? In that case you would most likely want to let
    > that decoration fail silently.


    Silently failing is completely non-pythonic. If you really wanted to
    handle a missing decorator, something like
    missingdec = lambda x:x
    would do this for you.

    > Decorators in general are the right solution for the wrong problem (as I
    > detailed in another thread). They are being introduced much too
    > prematurely, and have not been given time to be able to have been thought
    > through well enough. The @ syntax is the result of trying to shoehorn too
    > many solutions into one fix.


    Too prematurely?? staticmethod and classmethod were introduced in 2.2!
    PyObjC, ctypes, Jython and IronPython can all do with using them, as can
    rather a lot of other chunks of code. Anything that applies metadata to
    functions can use this - look at all the various places where people are
    putting stuff in docstrings as a current hack.

    > They purport to solve the problems of function type declaration
    > (class/static), function attributes, runtime type checking, and general
    > function mangling, when each of these (save general function mangling)
    > already have distinct solutions in nearly every other language. The first
    > three problems are currently implemented as hacks in Python that happen to
    > fall under the category of "general function mangling". Streamlining the
    > hack is not the answer.


    Or, alternately, they're another tool in the toolbox, along with
    metaclasses and
    the like.

    Anthony
    Anthony Baxter, Aug 5, 2004
    #6
  7. On Fri, 6 Aug 2004 02:41:10 +1000, Anthony Baxter
    <> wrote:
    > On Thu, 5 Aug 2004 12:29:51 -0400, Christopher T King <> wrote:
    > > What does one do if a decorator raises an exception?

    >
    > def deco(func):
    > raise TypeError
    >
    > @deco
    > def foo():
    > print "hello"


    Sigh. I missed this bit of cut-n-paste:

    Traceback (most recent call last):
    File "f.py", line 4, in ?
    @deco
    File "f.py", line 2, in deco
    raise TypeError
    TypeError
    Anthony Baxter, Aug 5, 2004
    #7
  8. Am Donnerstag, 5. August 2004 18:29 schrieb Christopher T King:
    > They purport to solve the problems of function type declaration
    > (class/static), function attributes, runtime type checking, and general
    > function mangling, when each of these (save general function mangling)
    > already have distinct solutions in nearly every other language. The first
    > three problems are currently implemented as hacks in Python that happen to
    > fall under the category of "general function mangling". Streamlining the
    > hack is not the answer.


    I don't think they try to solve all the things you state. Rather, it's only
    about general function mangling at compile time. Whatever you need to do for
    function mangling, that's up to you.

    And, at least for me, as I stated elsewhere, the syntax is just fine. I've
    tried it out yesterday, porting some code to 2.4a2 which used thread locks
    extensively, and just writing a little class InstanceSynchronizer() which is
    just a Class which defines __call__ (when decorating a function) and gets the
    first parameter from the function call to acquire an instance specific lock
    is certainly the right way to go.

    Think of the following: (old style)

    class x(object):
    def __init__(self):
    self.lock = threading.RLock()

    def synchronized_method(self):
    self.lock.acquire()
    try:
    <bla>
    finally:
    self.lock.release()

    That's just plain horrible compared to what @ decorators can do:

    class x(object):
    synchronized = InstanceSynchronizer()

    @synchronized
    def synchronized_method(self):
    <bla>

    Writing the InstanceSynchronizer is pretty easy too:

    class InstanceSynchronizer(object):

    def __init__(self):
    self._locks = {}
    self._refs = {}

    def _delete_ref(self,ref):
    del self._locks[self._refs[id(ref)][1]]
    del self._refs[id(ref)]

    def __call__(self,f):
    def fsyn(fself,*args,**kwargs):
    try:
    lock = self._locks[id(fself)]
    except KeyError:
    lock = threading.RLock()
    fselfref = weakref.ref(fself,self._delete_ref)
    self._locks[id(fself)] = lock
    self._refs[id(fselfref)] = (fselfref,id(fself))
    lock.acquire()
    try:
    return f(fself,*args,**kwargs)
    finally:
    lock.release()
    return fsyn

    This little class takes care of everything needed for instance locks. Writing
    a class that takes care of class locks for functions (in case you need to
    update class data) is easy as pie too.

    class ClassSynchronizer(object):

    def __init__(self):
    self._lock = threading.RLock()

    def __call__(self,f):
    def fsyn(*args,**kwargs):
    self._lock.acquire()
    try:
    return f(*args,**kwargs)
    finally:
    self._lock.release()
    return fsyn

    Now, if you have these two utility classes at your disposal, you can do the
    following:

    class someobject(object):
    __instances__ = {}
    isynchronized = InstanceSynchronizer()
    csynchronized = ClassSynchronizer()

    @csynchronized
    def __init__(self):
    <work on self.__instances__>

    @isynchronized
    @csynchronized
    def do_something(self):
    <work on self.__instances__ and on self>

    @isynchronized
    def do_somethingelse(self):
    <work only on self>

    Now tell me that using decorators to do synchronization isn't a lot easier to
    read than the first (old) example is, and also less error-prone (resp.
    acquiring/releasing locks properly and without deadlocks).

    Heiko.
    Heiko Wundram, Aug 5, 2004
    #8
  9. On Fri, 6 Aug 2004, Anthony Baxter wrote:

    > On Thu, 5 Aug 2004 12:29:51 -0400, Christopher T King <> wrote:
    > > What does one do if a decorator raises an exception?

    >
    > def deco(func):
    > raise TypeError
    >
    > @deco
    > def foo():
    > print "hello"


    Yes yes yes, I /know/ they are /able/ to raise exceptions. My point was
    about handling them in a clean, concise way.

    > Silently failing is completely non-pythonic.


    Then let's say you want to print a warning, "Warning, type checking not
    installed!"

    > If you really wanted to handle a missing decorator, something like
    > missingdec = lambda x:x would do this for you.


    Ick. That doesn't fix the general case (though I admit it wouldn't come
    up too often).

    > > Decorators in general are the right solution for the wrong problem (as I
    > > detailed in another thread). They are being introduced much too
    > > prematurely, and have not been given time to be able to have been thought
    > > through well enough. The @ syntax is the result of trying to shoehorn too
    > > many solutions into one fix.

    >
    > Too prematurely?? staticmethod and classmethod were introduced in 2.2!


    I'm referring to the syntax, not the decorators themselves.

    > PyObjC, ctypes, Jython and IronPython can all do with using them, as can
    > rather a lot of other chunks of code. Anything that applies metadata to
    > functions can use this - look at all the various places where people are
    > putting stuff in docstrings as a current hack.


    Anything that applies metadata to functions can use function attributes
    much more effictively. They're cleaner, more to the point, and are likely
    to have much less backlash than @. Example of a previous function
    attribute proposal:

    def foo(a,b,c):
    .accepts = (int,int,int)
    .returns = str
    pass

    > Or, alternately, they're another tool in the toolbox, along with
    > metaclasses and the like.


    It just so happens I'm not a big fan of metaclasses, either ;)
    Christopher T King, Aug 5, 2004
    #9
  10. On Thu, 5 Aug 2004, Heiko Wundram wrote:

    > Now tell me that using decorators to do synchronization isn't a lot easier to
    > read than the first (old) example is, and also less error-prone (resp.
    > acquiring/releasing locks properly and without deadlocks).


    I'll admit synchronization is a strong use case (since I don't believe it
    justifies language support, like it has in Java), but I just think there's
    a better way to go about things that no-one's thought of yet.
    Christopher T King, Aug 5, 2004
    #10
  11. Anthony Baxter

    Casey Duncan Guest

    On Thu, 5 Aug 2004 18:51:08 +0200
    Heiko Wundram <> wrote:

    [..]
    > Think of the following: (old style)
    >
    > class x(object):
    > def __init__(self):
    > self.lock = threading.RLock()
    >
    > def synchronized_method(self):
    > self.lock.acquire()
    > try:
    > <bla>
    > finally:
    > self.lock.release()
    >
    > That's just plain horrible compared to what @ decorators can do:


    Seems clear to me.
    >
    > class x(object):
    > synchronized = InstanceSynchronizer()
    >
    > @synchronized
    > def synchronized_method(self):
    > <bla>
    >
    > Writing the InstanceSynchronizer is pretty easy too:
    >
    > class InstanceSynchronizer(object):
    >
    > def __init__(self):
    > self._locks = {}
    > self._refs = {}
    >
    > def _delete_ref(self,ref):
    > del self._locks[self._refs[id(ref)][1]]
    > del self._refs[id(ref)]
    >
    > def __call__(self,f):
    > def fsyn(fself,*args,**kwargs):
    > try:
    > lock = self._locks[id(fself)]
    > except KeyError:
    > lock = threading.RLock()
    > fselfref = weakref.ref(fself,self._delete_ref)
    > self._locks[id(fself)] = lock
    > self._refs[id(fselfref)] = (fselfref,id(fself))
    > lock.acquire()
    > try:
    > return f(fself,*args,**kwargs)
    > finally:
    > lock.release()
    > return fsyn


    I will grant you that InstanceSynchronizer is reusable, but look at the
    volume of code here compared to the first example. I find the latter
    much more complex. Regardless, decorators don't really make this pattern
    possible, you could just as easily do this in 2.3:

    class x(object):
    synchronized = InstanceSynchronizer()

    def method(self):
    <bla>
    method = synchronized(method)

    The primary argument against this is that the rebinding is hidden down
    after the method body. I personally don't find that to be a problem, and
    the advantage is that it is neither a new concept nor a new syntax for
    people to learn and understand. It simply leverages what is already
    there and is nice and explicit.

    [..]
    > Now tell me that using decorators to do synchronization isn't a lot
    > easier to read than the first (old) example is, and also less
    > error-prone (resp. acquiring/releasing locks properly and without
    > deadlocks).


    I don't disagree that it is better and more general than your first
    example, however, a better and more general technique to do this already
    existed before the new decorator syntax.

    I just don't feel that the superficial gain of moving the declaration
    above the method definition is worth the added complexity to the
    language.

    -Casey
    Casey Duncan, Aug 5, 2004
    #11
  12. > I'll admit synchronization is a strong use case (since I don't believe it
    > justifies language support, like it has in Java), but I just think there's
    > a better way to go about things that no-one's thought of yet.


    The discussion's been going on python-dev since at least February
    2002. No better solution has been found yet.
    Anthony Baxter, Aug 5, 2004
    #12
  13. In article <>,
    Christopher T King <> wrote:

    > On Fri, 6 Aug 2004, Anthony Baxter wrote:
    >
    > > On Thu, 5 Aug 2004 12:29:51 -0400, Christopher T King <>
    > > wrote:
    > > > What does one do if a decorator raises an exception?

    > >
    > > def deco(func):
    > > raise TypeError
    > >
    > > @deco
    > > def foo():
    > > print "hello"

    >
    > Yes yes yes, I /know/ they are /able/ to raise exceptions. My point was
    > about handling them in a clean, concise way.


    What do you do if any other piece of code raises an exception?
    Why do you think decorators should be any different?

    If this is an actual possibility, there's nothing preventing you from
    wrapping a decorated def inside a try-except block.

    --
    David Eppstein
    Computer Science Dept., Univ. of California, Irvine
    http://www.ics.uci.edu/~eppstein/
    David Eppstein, Aug 5, 2004
    #13
  14. On Thu, 5 Aug 2004, Christopher T King wrote:

    > On Thu, 5 Aug 2004, Heiko Wundram wrote:
    >
    > > Now tell me that using decorators to do synchronization isn't a lot easier to
    > > read than the first (old) example is, and also less error-prone (resp.
    > > acquiring/releasing locks properly and without deadlocks).

    >
    > I'll admit synchronization is a strong use case (since I don't believe it
    > justifies language support, like it has in Java), but I just think there's
    > a better way to go about things that no-one's thought of yet.


    Replying to myself here...

    Why would one necessarily use method synchronization in Python, since any
    well-designed Python function should be re-entrant (though I'm sure there
    is the rare exception)? It would seem that data access synchronization is
    all that's needed for most threaded applications, and the only way to
    apply that is through the try/finally construct, since Python does not
    (yet?) provide built-in data synchronization.

    Of course, sometimes all a function does is access a synchronized piece of
    data (especially in the case of accessor functions used to simulate
    synchronized data access), in which case method synchronization is
    equivalent to the synchronization of that piece of data, and decorators
    can be applied to the method as a whole.
    Christopher T King, Aug 5, 2004
    #14
  15. On Thu, 5 Aug 2004, David Eppstein wrote:

    > If this is an actual possibility, there's nothing preventing you from
    > wrapping a decorated def inside a try-except block.


    And then being forced to duplicate the function definition. The way
    around this is, of course, to decorate manually, but then your decorators
    are segmented (some at the top of the function, some at the bottom).
    Christopher T King, Aug 5, 2004
    #15
  16. In article <>,
    Christopher T King <> wrote:

    > On Thu, 5 Aug 2004, David Eppstein wrote:
    >
    > > If this is an actual possibility, there's nothing preventing you from
    > > wrapping a decorated def inside a try-except block.

    >
    > And then being forced to duplicate the function definition. The way
    > around this is, of course, to decorate manually, but then your decorators
    > are segmented (some at the top of the function, some at the bottom).


    Let me get this straight: you're envisioning a situation in which you
    want to decorate a function, the decorator might fail, and if it does
    you want to do something else (perhaps including not decorating it at
    all), but with the same function body?

    If so, that's easy:

    def my_robust_decorator(func):
    try:
    return decorator_that_might_fail(func)
    except:
    return something_else

    @my_robust_decorator
    def func(args...):
    ....


    So what's the problem?

    --
    David Eppstein
    Computer Science Dept., Univ. of California, Irvine
    http://www.ics.uci.edu/~eppstein/
    David Eppstein, Aug 5, 2004
    #16
  17. On Thu, 5 Aug 2004, David Eppstein wrote:

    > Let me get this straight: you're envisioning a situation in which you
    > want to decorate a function, the decorator might fail, and if it does
    > you want to do something else (perhaps including not decorating it at
    > all), but with the same function body?


    Correct.

    > If so, that's easy:
    >
    > def my_robust_decorator(func):
    > try:
    > return decorator_that_might_fail(func)
    > except:
    > return something_else
    >
    > @my_robust_decorator
    > def func(args...):
    > ....


    Well, you've found a good solution. I stand corrected.
    Christopher T King, Aug 5, 2004
    #17
  18. Anthony Baxter

    Ivan Voras Guest

    Heiko Wundram wrote:

    >
    > class someobject(object):
    >
    > @synchronized
    > @classmethod
    > def x(cls):
    > pass
    >
    > If I were to translate this to english, I could read it as follows (note the
    > order):
    >
    > Define a _class someobject_ which has a _synchronized_ _classmethod_ x.


    FWIW, I, for example, don't have a problem with the notion of
    decorators, but I think the above syntax is just plain ugly. Why not use:

    def @synchronized @classmethod x(self):
    pass

    ?

    Granted that the keywords are long-ish, but I stongly feel it's still
    less ugly than the topmost version.


    --
    What part of "Ph'nglui mglw'nath Cthulhu R'lyeh wgah'nagl fhtagn" don't
    you understand?
    Ivan Voras, Aug 5, 2004
    #18
  19. Anthony Baxter

    Peter Hansen Guest

    Ivan Voras wrote:

    > def @synchronized @classmethod x(self):
    > pass
    >
    > Granted that the keywords are long-ish, but I stongly feel it's still
    > less ugly than the topmost version.


    I don't think the decorator names are ever keywords. They are
    just arbitrary names bound to stuff... I suspect you would find
    people writing code like this instead:

    sync = synchronized
    cm = classmethod

    def @sync @cm x(self):
    pass


    (I'm not saying whether that's a good thing, just pointing it out.)

    -Peter
    Peter Hansen, Aug 6, 2004
    #19
  20. On Fri, 06 Aug 2004 08:05:15 -0400, Peter Hansen <> wrote:
    > I don't think the decorator names are ever keywords. They are
    > just arbitrary names bound to stuff... I suspect you would find
    > people writing code like this instead:
    >
    > sync = synchronized
    > cm = classmethod
    >
    > def @sync @cm x(self):
    > pass
    >
    > (I'm not saying whether that's a good thing, just pointing it out.)


    I'm happy to say that I think this looks horrible ;)
    Anthony Baxter, Aug 6, 2004
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Anthony Baxter

    RELEASED Python 2.4, alpha 1

    Anthony Baxter, Jul 9, 2004, in forum: Python
    Replies:
    22
    Views:
    589
    Irmen de Jong
    Jul 16, 2004
  2. Mike C. Fletcher

    Re: RELEASED Python 2.4, alpha 1

    Mike C. Fletcher, Jul 9, 2004, in forum: Python
    Replies:
    16
    Views:
    495
    Mike C. Fletcher
    Jul 12, 2004
  3. Anthony Baxter

    RELEASED Python 2.4, alpha 2

    Anthony Baxter, Aug 5, 2004, in forum: Python
    Replies:
    0
    Views:
    250
    Anthony Baxter
    Aug 5, 2004
  4. =?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=

    Re: [Python-Dev] RELEASED Python 2.4, alpha 2

    =?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=, Aug 5, 2004, in forum: Python
    Replies:
    9
    Views:
    388
    =?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=
    Aug 10, 2004
  5. Anthony Baxter

    RELEASED Python 2.4, alpha 3

    Anthony Baxter, Sep 3, 2004, in forum: Python
    Replies:
    0
    Views:
    313
    Anthony Baxter
    Sep 3, 2004
Loading...

Share This Page