Thanks all for the responses. I read thought them carefully and address each below. I don't think any fully address the core problem - The "Argument" - the tuple of (type, default, documentation) - is currently not a first-class entity. Because there is no way to reference an Argument, there is much copypasta and dangerous-default-duplication. The idea of this proposal is that it should be possible to define an argument in one place, and simply bind a different name to it in each function signature. To recap - the points to the proposal are: - Allow documentation to be bound to an argument: "func(arg_a: int = 3 ? 'doc about arg', ...)" or "func(arg_a: int = 3 # 'doc about arg', ...)" - Allow reference to argument: "outer_func(new_arg_a_name: func.args.arg_a.type = func.args.arg_a.default ? 'new doc for arg a', ...)" - (optionally) a shorthand syntax for reusing type/doc/default of argument: "def outer_func(new_arg_a_name :=? func.args.arg_a, ...):" Below I have responded to each comment - please let me know if I missed something: ---------- On Thu, Apr 25, 2019 at 3:59 PM Robert Vanden Eynde <robertve92@gmail.com> wrote:
Looks like a more complicated way to say : def f(x:'int : which does stuff' = 5, y:'int : which does more stuffs')
I hadn't though of incorporating documentation into the type, that's a nice idea. I think it's an ok "for now" solution but: - doing it this way loses the benefits of type inspection (built in to most IDEs now), - does not allow you do for instance keep the type definition in the wrapper while changing the documentation. - Provides no easy way to reference (f.args.x.documentation) which is a main point to the proposal. ---------- On Thu, Apr 25, 2019 at 3:58 PM Chris Angelico <rosuav@gmail.com> wrote:
@functools.passes_args(f) def wrapper(spam, ham, *a, **kw): f(*a, **kw) ....
If that were implemented, would it remove the need for this new syntax
you propose?
This does indeed allow defaults and types to be passed on, but I find a this approach still has the basic flaw of using **kwargs: - It only really applies to "wrappers" - functions that wrap another function. The goal here is to address the common case of a function passing args to a number of functions within it. - It is assumed that the wrapper should use the same argument names as the wrapped function. A name should bind a function to an argument - but here the name is packaged with the argument. - It remains difficult to determine the arguments of "wrapper" by simple inspection - added syntax for removal of certain arguments only complicates the task and seems fragile (lest the wrapped functions argument names change). - Renaming an argument to "f" will change the change the arguments of wrapper - but in a way that's not easy to inspect (so for instance if you have a call "y = wrapper(arg_1=4)", and you change "f(arg1=....)" to "f(arg_one=...)" no IDE will catch that and make the appropriate change to "y=wrapper(arg_one=4)". - What happens if you're not simply wrapping one sub-function but calling several? What about when those subfunctions have arguments with the same name? ---------- On Thu, Apr 25, 2019 at 5:50 PM David Mertz <mertz@gnosis.cx> wrote:
Why not just this in existing Python: def func_1( a: int = 1 # 'Something about param a', b: float = 2.5 # 'Something else about param b', ) -> float: """Something about func_1
a and b interact in this interesting way. a should be in range 0 < a < 125 floor(b) should be a prime number
Something about return value of func_1 returns a multiplication """ return a*b
- This would currently be a syntax error (because "#" is before the comma), but sure we could put it after the comma. - It does not address the fact that we cannot reference "func_1.a.default" - which is one of the main points of this proposal. - I'm fine with "#" being the documentation operator instead of "?", but figured people would not like it because it breaks the precedent of anything after "#" being ignored by the compiler --------------- On Thu, Apr 25, 2019 at 9:04 PM Anders Hovmöller <boxed@killingar.net> wrote:
Maybe something like... def foo(**kwargs): “”” @signature_by: full.module.path.to.a.signature_function(pass_kwargs_to=bar, hardcoded=[‘quux’]) “”” return bar(**kwargs, quux=3)
This makes it difficult to see what the names of arguments to "foo" are, at a glance. And what happens if (as in the example) "foo" does not simply wrap a function, but distributes arguments to multiple subfunctions? (this is a common case) ---------------------------- On Fri, Apr 26, 2019 at 2:18 AM Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:
What I would rather see is
(1) Comment syntax "inside" (fvo "inside" including any comment after the colon but before docstring or other code) .....
(2) asserts involving parameters lexically are available to help().....
(1) I'm fine with "#" being used instead of "?" as the "documentation operator", but I figured it would be rejected for breaking the president that everything after "#" is ignored by the compiler. (2) This would be a nice addition ... if this proposal were actually implemented, you'd have a built in "Argument" object, and in that case you could do e.g.: RGB_IMAGE = Argument(type=np.ndarray, doc = 'An RGB image', check = lambda img: (img.ndim==3 and img.shape[2]==3)) def brighten_image(image :=? RGB_IMAGE, ...): ...