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/