[Python-Dev] Re: Call for defense of @decorators (original) (raw)
Andrew Durdin adurdin at gmail.com
Sun Aug 8 16:17:23 CEST 2004
- Previous message: [Python-Dev] Re: Call for defense of @decorators
- Next message: [Python-Dev] Re: Call for defense of @decorators
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Having just gone through the wiki page again, I think the last example under A (quoted below) shows up very plainly the only really serious problem with the before-def decorator syntax:
class TestDecorators(unittest.TestCase):
...
def test_dotted(self):
decorators = MiscDecorators()
@decorators.author('Cleese')
def foo(): return 42
self.assertEqual(foo(), 42)
self.assertEqual(foo.author, 'Cleese')
Suppose that you were not familiar enough with python to have heard of decorators: looking at this code, would you have any idea that the @ statement (potentially) fundamentally affects the behaviour of the foo() function? Is there anything except their proximity to suggest that they are interdependent? The only implication that they might be is the second assertEqual call, and that is by no means obvious.
On the other hand, the after-def (but before-colon) variants clearly imply that the decorators are related to the function definition -- the reader might not understand their purpose, but they will not fail to connect them with the function.
And here is a response to Guido's comments on the list-after-def syntax in another thread that were then incorporated into the wiki page.
Guido> - it hides crucial information (e.g. that it is a static method) after the signature, where it is easily missed
Not at all! The list of decorators would be a part of the signature. The decorators will be no more easily missed than the name of the last argument, which is arguably just as crucial.
Guido> - it's easy to miss the transition between a long argument list and a long decorator list
True. This is the main reason why having the list set off from the argument list with a keyword or symbol would be preferred; but suitable formatting would minimise the risk anyway -- see the example further below.
Guido> - it's cumbersome to cut and paste a decorator list for reuse, because it starts and ends in the middle of a line
This is (IMHO) a very weak argument. A decorator list with one or two decorators will probably be just as quick to type as to copy and paste with the before-def syntax, when the time to scroll between lines is taken into account (unless you're using a mouse, in which case highlighting within a line is not slow at all). Moreover, in more complicated decorator lists, the lists would likely be different (reducing the advantage of copy+paste); or if not, if you regularly use the same long decorator list, you're much better off defining your own decorator which applies those from the list, and then using that one repeatedly -- this will avoid errors and make maintenance easier.
Guido> Given that the whole point of adding decorator syntax is to move the decorator from the end ("foo = staticmethod(foo)" after a 100-line body) to the front, where it is more in-your-face, it should IMO be moved all the way to the front.
I disagree. Having the decorator at the end, after the function body, is obviously far from ideal, as it is extremely easy to miss; but the decorators are not the most important part of the function definition. The most important part (which should be most prominent, and thus first) is the "def" keyword introducing the function definition, and the function name. Whether the decorators are more or less important than the arguments (and thus which should come first) is less certain.
The example of a long decorated function declaration that Guido gives was:
def longMethodNameForEffect(longArgumentOne=None, longArgumentTwo=42) [ staticmethod, funcattrs(grammar="'@' dotted_name [ '(' [arglist] ')' ]", status="experimental", author="BDFL") ]:
I don't think this is as clear as it could be (and an argument from the "ugliness" of syntax should be using the clearest possible formatting) -- breaking the line before the decorator list, and indenting the decorator list one more level (to set it off from the docstring/body) makes the whole much clearer, and prevents the decorator list from being confused with the arguments:
def longMethodNameForEffect(longArgumentOne=None,
longArgumentTwo=42)
[staticmethod,
funcattrs(grammar="'@' dotted_name [ '(' [arglist] ')' ]",
status="experimental", author="BDFL")]:
(Having the [ and ]: on their own lines at the same indentation level may be clearer yet)
-- Andrew Durdin.
- Previous message: [Python-Dev] Re: Call for defense of @decorators
- Next message: [Python-Dev] Re: Call for defense of @decorators
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]