On Wed, 6 May 2020 at 15:08, Ricky Teachey <ri...@teachey.org> wrote:
>
> On Wed, May 6, 2020 at 1:44 PM Alex Hall <alex.moj...@gmail.com> 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 -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/XCXGW52MYQ2GA4I5NJ7H7BE5ZU7W2PCX/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to