<div dir="auto">Looks like a more complicated way to say :<div dir="auto"><br></div><div dir="auto">def f(x:'int : which does stuff' = 5, y:'int : which does more stuffs')</div><div dir="auto"><br></div><div dir="auto">The code reading the annotations (like the linter) might then parse it simply using .split.<br><br><div data-smartmail="gmail_signature" dir="auto"><a href="http://robertvandeneynde.be">robertvandeneynde.be</a></div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Le ven. 26 avr. 2019 à 00:41, Peter O'Connor <<a href="mailto:peter.ed.oconnor@gmail.com">peter.ed.oconnor@gmail.com</a>> a écrit :<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><font face="arial, helvetica, sans-serif">Dear all,</font><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">Despite the general beauty of Python, I find myself constantly violating the "don't repeat yourself" maxim when trying to write clear, fully documented code. Take the following example:</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><div><font face="arial, helvetica, sans-serif"> def func_1(a: int = 1, b: float = 2.5) -> float:</font></div><div><font face="arial, helvetica, sans-serif"> """</font></div><div><font face="arial, helvetica, sans-serif"> Something about func_1</font></div><div><font face="arial, helvetica, sans-serif"> :param a: Something about param a</font></div><div><font face="arial, helvetica, sans-serif"> :param b: Something else about param b</font></div><div><font face="arial, helvetica, sans-serif"> :return: Something about return value of func_1</font></div><div><font face="arial, helvetica, sans-serif"> """</font></div><div><font face="arial, helvetica, sans-serif"> return a*b</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif"> def func_2(c:float=3.4, d: bool =True) -> float:</font></div><div><font face="arial, helvetica, sans-serif"> """</font></div><div><font face="arial, helvetica, sans-serif"> Something about func_2</font></div><div><font face="arial, helvetica, sans-serif"> :param c: Something about param c</font></div><div><font face="arial, helvetica, sans-serif"> :param d: Something else about param d</font></div><div><font face="arial, helvetica, sans-serif"> :return: Something about return value</font></div><div><font face="arial, helvetica, sans-serif"> """</font></div><div><font face="arial, helvetica, sans-serif"> return c if d else -c</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif"> def main_function(a: int = 1, b: float = 2.5, d: bool = True) -> float:</font></div><div><font face="arial, helvetica, sans-serif"> """</font></div><div><font face="arial, helvetica, sans-serif"> Something about main_function</font></div><div><font face="arial, helvetica, sans-serif"> :param a: Something about param a</font></div><div><font face="arial, helvetica, sans-serif"> :param b: Something else about param b</font></div><div><font face="arial, helvetica, sans-serif"> :param d: Something else about param d</font></div><div><font face="arial, helvetica, sans-serif"> :return: Something about return value</font></div><div><font face="arial, helvetica, sans-serif"> """</font></div><div><font face="arial, helvetica, sans-serif"> return func_2(func_1(a=a, b=b), d=d)</font></div></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><div><font face="arial, helvetica, sans-serif">Which has the following problems:</font></div><div><font face="arial, helvetica, sans-serif">- Defaults are defined in multiple places, which very easily leads to bugs (I'm aware of **kwargs but it obfuscates function interfaces and usually does more harm than good)</font></div><div><font face="arial, helvetica, sans-serif">- Types are defined in multiple places</font></div><div><font face="arial, helvetica, sans-serif">- Documentation is copy-pasted when referencing a single thing from different places. (I can't count the number of types I've written ":param img: A (size_y, size_x, 3) RGB image" - I could now just reference a single RGB_IMAGE_DOC variable)</font></div><div><font face="arial, helvetica, sans-serif">- Argument names need to be written twice - in the header and documentation - and it's up to the user / IDE to make sure they stay in sync.</font></div></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">I propose to resolve this with the following changes:</font></div><div><font face="arial, helvetica, sans-serif">- Argument/return documentation can be made inline with a new "?" operator. Documentation becomes a first class citizen.</font></div><div><font face="arial, helvetica, sans-serif">- Argument (type/default/doc) can be referenced by "</font><span style="font-family:arial,helvetica,sans-serif">func</span><font face="arial, helvetica, sans-serif">.args.<arg_name>.type" / "</font><span style="font-family:arial,helvetica,sans-serif">func</span><font face="arial, helvetica, sans-serif">.args.<arg_name>.default" / "</font><span style="font-family:arial,helvetica,sans-serif">func</span><font face="arial, helvetica, sans-serif">.args.<arg_name>.doc". Positional reference: e.g. "</font><span style="font-family:arial,helvetica,sans-serif">func</span><font face="arial, helvetica, sans-serif">.args[1].default" also allowed. If not specified, they take a special, built-in "Undefined" value (because None may have another meaning for defaults). Return type/doc can be referenced with "</font><span style="font-family:arial,helvetica,sans-serif">func</span><font face="arial, helvetica, sans-serif">.return.type" / "</font><span style="font-family:arial,helvetica,sans-serif">func</span><font face="arial, helvetica, sans-serif">.return.doc".</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">This would result in the following syntax:</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><div><font face="arial, helvetica, sans-serif"> def func_1(</font></div><div><font face="arial, helvetica, sans-serif"> a: int = 1 ? 'Something about param a',</font></div><div><font face="arial, helvetica, sans-serif"> b: float = 2.5 ? 'Something else about param b',</font></div><div><font face="arial, helvetica, sans-serif"> ) -> float ? 'Something about return value of func_1':</font></div><div><font face="arial, helvetica, sans-serif"> """ Something about func_1 """</font></div><div><font face="arial, helvetica, sans-serif"> return a*b</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif"> def func_2(</font></div><div><font face="arial, helvetica, sans-serif"> c: float=3.4 ? 'Something about param c',</font></div><div><font face="arial, helvetica, sans-serif"> d: bool =True ? 'Something else about param d',</font></div><div><font face="arial, helvetica, sans-serif"> ) -> float ? 'Something about return value':</font></div><div><font face="arial, helvetica, sans-serif"> """ Something about func_2 """</font></div><div><font face="arial, helvetica, sans-serif"> return c if d else -c</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif"> def main_function(</font></div><div><font face="arial, helvetica, sans-serif"> a: func_1.args.a.type = func_1.args.a.default ? func_1.args.a.doc,</font></div><div><font face="arial, helvetica, sans-serif"> b: func_1.args.b.type = func_1.args.b.default ? func_1.args.b.doc,</font></div><div><font face="arial, helvetica, sans-serif"> d: func_2.args.d.type = func_2.args.d.default ? func_2.args.d.doc,</font></div><div><font face="arial, helvetica, sans-serif"> ) -> func_2.return.type ? func2.return.doc:</font></div><div><font face="arial, helvetica, sans-serif"> """ Something about main_function """</font></div><div><font face="arial, helvetica, sans-serif"> return func_2(func_1(a=a, b=b), d=d)</font></div></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">If the main_function header seems repetitious (it does) we could allow for an optional shorthand notation like:</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><div> def main_function(</div><div> a :=? func_1.args.a,</div><div> b :=? func_1.args.b,</div><div> d :=? func_2.args.d,</div><div> ) ->? func_2.return:</div><div> """ Something about main_function """</div><div> return func_2(func_1(a=a, b=b), d=d)</div></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">Where "a :=? func_1.args.a" means "argument 'a' takes the same type/default/documentation as argument 'a' of func_1". </font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">So what do you say? Yes it's a bold move, but I think in the long term it's badly needed. Perhaps something similar has been proposed already that I'm not aware of.</font></div></div>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank" rel="noreferrer">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
</blockquote></div>