On Wed, 6 May 2020 at 15:08, Ricky Teachey <[email protected]> wrote:
>
> On Wed, May 6, 2020 at 1:44 PM Alex Hall <[email protected]> wrote:
>>
>> I think this looks great, I can't think of anything wrong with it.
>>
>> Could we put this into the standard library, so that IDEs and linters are
>> programmed to recognise it?
>
>
> If it does cover the majority of corner cases, I think this is a great thing
> to consider.
>
> However on the other hand, wouldn't there be an advantage for the user to be
> able to make adjustments to the arguments before passing them along, and to
> be able to control WHEN the autoassign action occurs? Isn't this a very
> common type thing to do?
It cn be done, but we would be stepping away from "KISS" - and maybe,
if such control
is needed ina certain class, auto-assigning won't be a thing for it.
I guess the default being that arguments are already assigned to the instance
when __init__ starts would be the most common use case.
And if adjusts and
transforms are needed, they can be done inside __init__ as usual, the original
assignment will just be overwritten. In the case the class features
attributes that
trigger side-effects on assignment, then, unless you want them as passed,
maybe auto-assigment should not be used.
>
> Using the same example:
>
> class A:
> @autoassign
> def __init__(self, a, b, c=3):
> b = MyEnum(b)
>
> In the example above, self.b is assigned the value of b, not Enum(b).
Yes - that is a pattern I need a lot. Due to the considerations above,
I think the better approach would be to extend the autoassign
to pick this ("cast") transform from parameter annotations or from optional
parameters to "@autoassign"
> And even if you called-- or gave the option to call-- func(*args, **kwargs)
> first,
> autoassign still wouldn't know that you want to modify the supplied
> parameter value.
> It seems to me like it would be more useful to be able to have access to some
> sort of
> partial namespace object, containing the objects that were passed to the
> function,
> that could then be passed along.... something like this:
>
> class A:
> def __init__(self, a, b, c=3):
> b = MyEnum(b)
> autoassign(A.get_partial_namespace())
>
> The get_partial_namespace() method would basically be the same as locals(),
> except:
> 1. the name bound to the object that called the function is excluded (self)
> and
> 2. any other names that were not part of the call of the function are
> excluded.
Yes, a mechanism to allow the actall assignment to the instancs to be
made in the middle of
"__init__" is feasible, and even something to make cause the
assignements to take place
on the return of "__init__" - but them, as I noted above, we are
complicating things -
if we accept that most such transforms of parameters are a "cast" like thing -
(and as noted, I need this pattern a lot) - maybe use annotations for that,
or, to avoid super-charge annotations with even more semantics, just allow
these 'transforms' to be indicated as parameters to auto-assign.
Ah - please tell me if something like this makes sense:
```
import typing as T
dev convert_to_enum(val: T.Union[MyEnum, int])->MyEnum:
return MyEnum(val)
class A:
@autoassign(transforms={"b": convert_to_enum})
def __init__(self, a: T.any, b: MyEnum, c: int=3):
#self.b is already assigned as a guaranteed 'MyEnum'
```
In that way, one could eventually come up with a static
linter/whatever that could
understand that. (And that would be a whole new level of complexity - the linter
would have to do a lot of twists to account for that).
Typing annotations apart, would the "transforms" parameter suffice
for what you are asking for?
It would work for the cases I need it
(in my largest personal project, I want to auto-promote
some arguments to "Point" and others to to "Color" objects,
and allow those to be called by passing 2-tuples and 3-tuples respectively)
As for the typing, on a second tough, in the case above, declaring the
instance attributes with
annotations normally would work - all the linters (including mypy)
would need to do
would be to "trust" @autoassign (it is that, or follow the
'transforms' argument)
```
class A:
a: T.any
b: MyEnum
c: int
@autoassign(cast_arguments=True)
def __init__(self, a: T.any, b: T.Union[int, MyEnum], c: int):
# everything already converted
```
This would require some extra code in autoassign,
so that it would have to "know" how to cast arguments
into the annotated attribute types. This would be nice,
but I am afraid it would be "too much" for a simple
stdlib inclusion. (One thing is if the annotation is
a callable type that could do the conversion by itself, another
is if the annotation is something like `b : T.List[T.Union[int, float]]`
The "transforms" parameter OTOH seems to be feasible.
>
> ---
> Ricky.
>
> "I've never met a Kentucky man who wasn't either thinking about going home or
> actually going home." - Happy Chandler
>
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/XCXGW52MYQ2GA4I5NJ7H7BE5ZU7W2PCX/
Code of Conduct: http://python.org/psf/codeofconduct/