Re: [Python-ideas] Augmented assignment syntax for objects.

2017-05-02 Thread Erik

On 26/04/17 21:50, Chris Angelico wrote:

On Thu, Apr 27, 2017 at 6:24 AM, Erik  wrote:

The background is that what I find myself doing a lot of for private
projects is importing data from databases into a structured collection of
objects and then grouping and analyzing the data in different ways before
graphing the results.

So yes, I tend to have classes that accept their entire object state as
parameters to the __init__ method (from the database values) and then any
other methods in the class are generally to do with the subsequent analysis
(including dunder methods for iteration, rendering and comparison etc).


You may want to try designing your objects as namedtuples. That gives
you a lot of what you're looking for.


I did look at this. It looked promising.

What I found was that I spent a lot of time working out how to subclass 
namedtuples properly (I do need to do that to add the extra logic - and 
sometimes some state - for my analysis) and once I got that working, I 
was left with a whole different set of boilerplate and special cases and 
therefore another set of things to remember if I return to this code at 
some point.


So I've reverted to regular classes and multiple assignments in __init__.

E.

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-05-02 Thread Brendan Barnwell

On 2017-05-01 11:50, Jerry Hill wrote:

>What happens if you use this syntax in a top-level function rather
>than a method? (Or a static method?)
>
>def function(x, y, x.attr):
> ...
>
>(And don't forget that behind the scenes, methods*are*  functions.) What
>would this syntax even mean?

It would mean the same thing as "def function(x, y, z):", which is:
take the first three positional arguments, and assign them to the
local names listed in the function definition.  The same as

def function(foo, bar, baz):
 x = foo
 y = bar
 x.attr = baz



>Or if you use some other name other than the first parameter?
>
>def method(self, spam, foo.eggs):
> ...

What's the problem?  How is this any different from
def method(self, bar, baz):
 spam = bar
 foo.eggs = baz

I mean, it does imply that 'foo' is some globally writable bit of
data, being modified via side effect of calling a method, which is
certainly a code smell.  Still, we're all consenting adults here, and
it doesn't seem any worse than the already-legal variant I mention
above.


	I don't think the existing cases are really parallel.  In the example 
with x.attr, you're introducing a dependency among different arguments. 
 That isn't currently possible.  You can't define a function like this:


def function(x, y, x):

	So there's never any question of which order function arguments are 
bound in.  In your system, what would happen if I do this:


def function(x.attr, x)

	Would this, when called, assign an attribute on whatever is referred to 
by a global variable x, and then, after that, create a local variable x 
(necessarily shadowing the global whose attribute I just set)?  You can 
argue that assigning in left-to-right order is the natural choice, and 
I'd agree, but that doesn't change the fact that introducing potential 
order dependency is new behavior.


	You also say that the existing behavior is "assign to local names", but 
that's just the thing.  "x.attr = blah" is not an assignment to a local 
name, because "x.attr" is not a name.  It's an attribute assignment, 
because "x.attr" is an attribute reference.  Those are very different 
things.  (The latter, for instance, can be hooked with __setattr__, but 
assignment to local names is not hookable.)  Right now you can only use 
function arguments to assign to local names.  But if you could start 
putting other things as function arguments, you could use them to assign 
to things that are not local names.  That is a major change.


--
Brendan Barnwell
"Do not follow where the path may lead.  Go, instead, where there is no 
path, and leave a trail."

   --author unknown
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-05-01 Thread Jerry Hill
On Thu, Apr 27, 2017 at 7:21 PM, Steven D'Aprano  wrote:
> On Wed, Apr 26, 2017 at 03:54:22PM -0400, Jerry Hill wrote:
>> On Tue, Apr 25, 2017 at 8:05 PM, Ryan Gonzalez  wrote:
>> > def ___init__(self, self.attr):
>>
>> I'm not a python developer, I'm just a developer that uses python.
>> That said, I really like this form.  It eliminates most of the
>> redundancy, while still being explicit.  It's true that you have to
>> repeat the 'self' name, but it feels like the right balance in my
>> mind.  It seems like anyone who's familiar with python function
>> definitions would immediately grasp what's going on.
>
> I don't like it, not even a bit. It's not general, "self" is effectively
> a special case. Consider:

I wasn't thinking that 'self' should be a special case at all.

> What happens if you use this syntax in a top-level function rather
> than a method? (Or a static method?)
>
> def function(x, y, x.attr):
> ...
>
> (And don't forget that behind the scenes, methods *are* functions.) What
> would this syntax even mean?

It would mean the same thing as "def function(x, y, z):", which is:
take the first three positional arguments, and assign them to the
local names listed in the function definition.  The same as

def function(foo, bar, baz):
x = foo
y = bar
x.attr = baz


> Or if you use some other name other than the first parameter?
>
> def method(self, spam, foo.eggs):
> ...

What's the problem?  How is this any different from
def method(self, bar, baz):
spam = bar
foo.eggs = baz

I mean, it does imply that 'foo' is some globally writable bit of
data, being modified via side effect of calling a method, which is
certainly a code smell.  Still, we're all consenting adults here, and
it doesn't seem any worse than the already-legal variant I mention
above.

> Conceptually, it is mixing up two distinct tasks:
>
> - declaring the parameter list of the function/method;
>
> - running part of the body of the method.

Is assigning your parameters to their local names really part of
'running the body of the method'?  I mean, I almost never write my
functions like this:

def fun(*args):
   foo = args[0]
   bar = args[1]
   baz = args[2]

Do you?  If not, aren't you using the function definition to assign
parameters to local names?  Also, if you do write functions that way,
aren't you *also* losing the semantic hints about what parameters are
acceptable and what they are used for?

> The parameter list of the method is the *interface* to the method: it
> tells you the public names and default values (and possibly types, if
> you use type annotations) of the method parameters. But this syntax
> overloads the parameter list to show part of the *implementation* of the
> method (namely, that some parameters are assigned directly to attributes
> of self). Every time the implementation changes, the parameter list will
> change too.

I guess I don't agree that the function definition only tells you the
'public names' of the parameters being passed.  Instead, I think the
function definition tells you the names those parameters are going to
go by inside the function.  That is, their local names. And if you're
taking the parameters and assigning them to attributes of self anyway,
then you have the exact same issue with your parameter list changing
every time the implementation changes anyway, don't you?

> it doesn't look so good in larger, more realistic cases, especially with
> other syntax. Here's a parameter list taken from some real code of mine,
> with the "self." syntax added:

I won't argue with that, I suppose.  I'm not convinced it's worse than
the status quo, but yes, if you pack all the possible options into
your parameters, you can end up with a messy function signature.  I
guess my python experience is atypical if most of your methods take 6+
parameters, including some that are keyword-only, most of which have
default values, and are annotated with type hints.

> class BinnedData(object):
> def __init__(self, self.number:int,
>self.start:float=None,
>self.end:float=None,
>self.width:float=None,
>*,
>self.policy=None,
>self.mark=False
>):
>
> The repetition of "self" is not only tedious and verbose, it adds
> noise to the parameter list and pushes the reader's attention away from
> the important part (the name of the parameter, e.g. "width") and to
> something irrelevant to the interface ("self").
>
> And I am not looking forward to having to explain to beginners to Python
> why this doesn't work:
>
> data = BinnedData(self.number = 8, self.start = 0, self.end = 20)

For what it's worth, if that construct wouldn't work, then I'm
convinced that the idea is a bad one. :)  I'm not sure I see why that
would have to be forbidden, though.

-- 
Jerry

Re: [Python-ideas] Augmented assignment syntax for objects.

2017-05-01 Thread Juancarlo Añez
On Thu, Apr 27, 2017 at 7:28 PM, Steven D'Aprano 
wrote:

> > In my experience, what Python is lacking is a way to declare attributes
> > outside of the constructor. Take a look at how it's done in C#, Swisft,
> or
> > Go.
>
> Since you apparently already know how they do it, how about telling us
> (1) how they do it, and (2) *why* they do it?
>

They make attribure declarations at the class declaration scope be instance
attributes. Python makes that kind of declaration class attributes (statics
in some other languages).

This is the spec for C#: https://goo.gl/FeBTuy


The reason *why* they do it that way is because declaring instance
fields/variables is much more frequent than declaring class ones.


> > Object attributes outside of the constructor would solve things more
> > relevant than the vertical space used when assigning constructor
> parameters
> > to attributes.
>
> Solve which things?
>

Instance attributes may be defined with or without default values without
having to pass them as arguments to or mention them in a constructor.


> > For example, multiple inheritance is well designed in
> > Python, except that it often requires constructors with no parameters,
> > which leads to objects with no default attributes.
>
> Can you elaborate?


A class hierarchy in which there is multiple inheritance requires
constructors with no arguments. This is typical: https://goo.gl/l54tx7

I don't know which would be the best syntax, but it would be convenient to
be able to declare something like:

class A:

var a = 'a'


And have "a"  be an instance attribute.

-- 
Juancarlo *Añez*
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-29 Thread Nick Coghlan
On 29 April 2017 at 09:51, Ivan Levkivskyi  wrote:
> typing.NamedTuple was already mentioned in this discussion, I just would
> like to add few comments:
>
> 1. I think that changing Python syntax to support declarative classes is not
> a realistic option in nearby future.
> In contrast, there is an existing syntax change - variable annotations -
> that can be actively experimented with.
> Variable annotations are designed to play well with metaclass machinery, for
> example, they will respect
> __prepare__ method, if it injects __annotations__ as a custom mapping, etc.
>
> 2. Possible strategy for declarative classes could be developing independent
> *composable* mixins/traits:
>
>   @comparable
>   @pickleable
>   class MyClass:
>   x: int
>   y: int
>
> or
>
>   class MyClass(Comparable, Pickleable):
>   x: int
>   y: int
>
> The problem with the second approach is that it can lead to metaclass
> conflicts. A possible solution will
> be to provide a standard metaclass for mixins in stdlib.

Between __init_subclass__, __set_name__, __annotations__, and
guaranteed order preservation for class namespaces, Python 3.6 has
provided some pretty powerful tools for folks to experiment with new
approaches to declarative class definitions.

One point worth considering is that given standard library
implementations of the explicit class decorator forms (e.g in the
`types` module, or in the modules defining the relevant protocols), it
should be relatively straightforward to create mixin classes that use
__init_subclass__ to implicitly apply the explicit decorators.

The same doesn't hold the other way around - given a mixin, it's
tricky to convert that to a class decorator form.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-29 Thread Nick Coghlan
On 29 April 2017 at 03:00, Mike Miller  wrote:
> On 2017-04-28 06:07, Nick Coghlan wrote:
>> For a *lot* of classes, what we want to be able to define is:
>>
>> - a set of data fields
>> - a basic initialiser to set those fields by name
>> - a repr based on those fields (or a subset)
>> - equality comparisons based on those fields (or a subset)
>> - ordering comparisons based on those fields (or a subset)
>> - conversion to a JSON-friendly dict
>> - pickling support
>> - copying support
>
>
> Nice!  I've implemented a higher-level base class in a few projects that
> does just this.  Things like pickling and JSON I might want to put into
> "mixins", but yes the majority of these would be nice to have implemented by
> default "batteries included" style.  I prefer a base class to decorators
> since they seem to stay out of the way more:
>
> class Vehicle(BaseObject, Picklable):
> …

Putting any questions of aesthetics aside, the main argument in favour
of using a base class and __init_subclass__ for autoclass definitions
would be the fact that further subclasses would automatically get the
magic method construction executed, rather than requiring that the
class decorator be repeated on the subclass.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-29 Thread Tin Tvrtković
On Fri, Apr 28, 2017 at 3:07 PM Nick Coghlan  wrote:

> Yes, the point I attempted to raise earlier: at the language design
> level, "How do we make __init__ methods easier to write?" is the
> *wrong question* to be asking. It's treating the symptom (writing an
> imperative initialiser is repetitive when it comes to field names)
> rather than the root cause (writing imperative initialisers is still
> part of the baseline recommendation for writing classes, and we don't
> offer any supporting infrastructure for avoiding that directly in the
> standard library) [...]
>


Very well put. I also can't help but hope these efforts lead to Python also
acquiring better tools for dealing with structured data (instances of
classes and enumerations) down the road. Like a Pythonic version of Rust's
match, for example. That would be really something.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-29 Thread Steven D'Aprano
On Fri, Apr 28, 2017 at 11:04:00PM +0100, Erik wrote:

> Isn't binding an object to a namespace the same operation that 
> assignment performs?

Yes.

> So it's a type of assignment, and one that doesn't require the name to 
> be spelled twice in the current syntax (and that's partly why I took 
> offense at a suggestion - not by you - that I was picking "random or 
> arbitrary" keywords. I picked it for that specific reason).

That was me.

You took *offense*?

For somebody who made it clear that you didn't care about this "self 
import name" suggestion, you sure are touchy to have it criticised.

Assignment is the least interesting and important thing that the import 
statement does. Many keywords do an name binding operation, not just 
import, but also:

for, with, except, def, class 

and most relevant to my comment:

del 

is actually defined by the documentation as a name binding operation. 

https://docs.python.org/3/reference/executionmodel.html

I'm sorry that the joke was too subtle, I did put a wink after it, but 
you deleted it from your reply.

The point is, import's name binding is the least interesting and least 
important thing that it does. We could have defined import to be a 
function that returns a module object, or a tuple of objects, and left 
the binding up to the caller:

# What If import were a function instead of a statement?
math = import("math")
sin, cos = import("math", "sin", "cos")

That's rather similar to what __import__ does, but of course import as a 
statement is a much better design. Nevertheless, we could take away the 
name-binding aspect of import, and it would still be recognisable as 
performing an import: it would search the module cache, search the path, 
load modules, compile the code, create module objects, and all the other 
things needed to import a module. The name binding (assignment) is just 
an convenience.

But take away the *import functionality*, and "import" is no longer an 
appropriate name. Why is it called import when it doesn't import 
anything? Because of the name binding? Well, these keywords all do name 
binding too, why can't we use them?

self for attr
self except attr
self def attr
self class attr

etc. I'm sorry that my posting style rubbed you the wrong way and made 
you defensive, by I stand by my comment: chosing import as the keyword 
to do something completely unrelated to importing is an arbitrary 
choice, and we might as well choose del (or def, or for) and save some 
typing.

If Python were the sort of language to use more symbols rather than 
names, like Perl, we could invent a bind to the left arrow operator:

self <- a, b, c

Well, that wouldn't work, because of operator precedence. But you get 
the idea. Or we could bind to the right:

a, b, c -> self


Make of them what you will.


-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-29 Thread Paul Moore
On 28 April 2017 at 23:04, Erik  wrote:
>> See what I mean? Things get out of hand *very* fast.
>
> I don't see how that's getting "out of hand". The proposal is nothing more
> complicated than a slightly-different spelling of assignment. It could be
> done today with a text-based preprocessor which converts the proposed form
> to an existing valid syntax. Therefore, if it's "out of hand" then so is the
> existing assignment syntax ;)

Well with your clarification, it's now clear to me that your proposal is for

 import ,  ...

to be equivalent to

_tmp = 
_tmp.var1 = var1
_tmp.var2 = var2
...
del _tmp

Please correct me if I'm wrong here - but that's what I get from your
comments. Note that the way I've described the proposal allows for an
*expression* on the left of import - that's simply because I see no
reason not to allow that (the whole "arbitrary restrictions" thing
again).

So based on the above, you're proposing reusing the import keyword for
a series of attribute assignments, on the basis that the current
meaning of import is to assign values to a number of attributes of the
current namespace. However, that misses the fact that the main point
of the current import statement is to do the *import* - the RHS is a
list of module names. The assignment is just how we get access to the
modules that have been imported. So by "reusing" the import keyword
purely by analogy with the assignment part of the current semantics,
you're ignoring the fundamental point of an import, which is to load a
module.

So based on your clarification, I'm now solidly against reusing the
"import" keyword, on the basis that your proposed syntax doesn't
import any modules.

On the other hand, the construct you describe above of repeated
attribute assignments is only really common in __init__ functions.
It's similar to the sort of "implied target" proposals that have been
raised before (based on the Pascal "with" statement and similar
constructs):

SOME_KEYWORD :
.var1 = var1
.var2 = var2

Your construct is more limited in that it doesn't allow the RHS of the
assignments to be anything other than a variable with the same name as
the attribute (unless you extend it with "expr as var", which I can't
recall if you included in your proposal), nor does it allow for
statements other than assignments in the block. And the implied target
proposal doesn't really avoid the verbosity that prompted your
proposal. So while it's similar in principle, it may not actually help
much in your case.

So the reason I was saying things got "out of hand" was because the
final version I got to had absolutely nothing to do with an import (in
my view) - but on reflection, you're right it's no different than the
self version. It's just that the self version also has nothing to do
with an import! However, in the original context, it's easier to see
"name injection into a namespace" as a common factor, and miss
"importing a module" as the key point (at least it was easier for me
to miss that - you may have seen that and been happy that your
proposal was unrelated to modules even though it used the import
keyword).

I agree with Nick - the place we should be looking for improvements
here is in trying to find abstractions for common patterns of class
creation. Instead of looking at how to make the low-level mechanisms
like __init__ easier to write, we should be concentrating on making it
rare for people to *need* to use the low-level forms (while still
leaving them present for specialised cases).

Paul
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-28 Thread Erik

On 28/04/17 10:47, Paul Moore wrote:

On 28 April 2017 at 00:18, Erik  wrote:

The semantics are very different and there's little or no connection
between importing a module and setting an attribute on self.


At the technical level of what goes on under the covers, yes. At the higher
level of what the words mean in spoken English, it's really not so different
a concept.


I disagree. If you were importing into the *class* (instance?) I might
begin to see a connection, but importing into self?


I know you already understand the following, but I'll spell it out 
anyway. Here's a module:


-
$ cat foo.py
def foo():
  global sys
  import sys

  current_namespace = set(globals().keys())
  print(initial_namespace ^ current_namespace)

def bar():
  before_import = set(locals().keys())
  import os
  after_import = set(locals().keys())
  print(before_import ^ after_import)

initial_namespace = set(globals().keys())
-

Now, what happens when I run those functions:

$ python3
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import foo
>>> foo.foo()
{'sys', 'initial_namespace'}
>>> foo.bar()
{'before_import', 'os'}
>>>

... so the net effect of "import" is to bind an object into a namespace 
(a dict somewhere). In the case of 'foo()' it's binding the module 
object for "sys" into the dict of the module object that represents 
'foo.py'. In the case of 'bar()' it's binding the module object for "os" 
into the dict representing the local namespace of the current instance 
of the bar() call.


Isn't binding an object to a namespace the same operation that 
assignment performs?


So it's a type of assignment, and one that doesn't require the name to 
be spelled twice in the current syntax (and that's partly why I took 
offense at a suggestion - not by you - that I was picking "random or 
arbitrary" keywords. I picked it for that specific reason).


I realize that there are other semantic changes (importing a module 
twice doesn't do anything - and specifically repeated "import * from 
mod" will not do anything if the module mutates) - and perhaps this is 
your point.



Also, if you try to make the obvious generalisations (which you'd *have* to be 
able to
make due to the way Python works) things quickly get out of hand:

def __init__(self, a):
self import a


self.a = a



OK, but self is just a variable name, so we can reasonably use a different name:

def __init__(foo, a):
foo import a


foo.a = a


So the syntax is  import 

Presumably the following also works, because there's nothing special
about parameters?

def __init__(x, a):
calc = a**2
x import calc


x.calc = calc


And of course there's nothing special about __init__

def my_method(self, a):
self import a


self.a = a


Or indeed about methods

def standalone(a, b):
a import b


a.b = b


or statements inside functions:

if __name __ == '__main__:
a = 12
b = 13
a import b


a.b = b


Hmm, I'd hope for a type error here. But what types would be allowed
for a?


I think you're assuming I'm suggesting some sort of magic around "self" 
or some such thing. I'm not. I've written above exactly what I would 
expect the examples to be equivalent to. It's just an assignment which 
doesn't repeat the name (and in the comma-separated version allows 
several names to be assigned using compact syntax without spelling them 
twice, which is where this whole thing spawned from).



See what I mean? Things get out of hand *very* fast.


I don't see how that's getting "out of hand". The proposal is nothing 
more complicated than a slightly-different spelling of assignment. It 
could be done today with a text-based preprocessor which converts the 
proposed form to an existing valid syntax. Therefore, if it's "out of 
hand" then so is the existing assignment syntax ;)


FWIW, I should probably state for the record that I'm not actually 
pushing for _anything_ right now. I'm replying to questions asked and 
also to statements made which I think have missed the point of what I 
was trying to say earlier. So I'm just engaging in the conversation at 
this point - if it appears confrontational then it's not meant to.



To summarise:

1. There's some serious technical issues with your proposal, which as
far as I can see can only be solved by arbitrary restrictions on how
it can be used


To be honest, I still don't understand what the serious technical issues 
are (other than the parser probably doesn't handle this sort of 
keyword/operator hybrid!). Is it just that I'm seeing the word "import" 
in this context as a type of assignment and you're seeing any reference 
to the word "import" as being a completely different type of operation 
that comes with baggage?


Regards, E.
___
Python-ideas mailing list
Python-ideas@python.org

Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-28 Thread Paul Moore
On 28 April 2017 at 14:07, Nick Coghlan  wrote:
>> Am I missing some point?
>
> Yes, the point I attempted to raise earlier: at the language design
> level, "How do we make __init__ methods easier to write?" is the
> *wrong question* to be asking. It's treating the symptom (writing an
> imperative initialiser is repetitive when it comes to field names)
> rather than the root cause (writing imperative initialisers is still
> part of the baseline recommendation for writing classes, and we don't
> offer any supporting infrastructure for avoiding that directly in the
> standard library)
[...]

Ah, OK. I see what you're saying here. I agree, that's the direction
we should be looking in. I'd sort of lumped all of that side of things
in my mind under the header of "must take a look at attrs" and left it
at that for now. My mistake.

So basically yes, I agree we should have better means for writing
common class definition patterns in a declarative way, retaining the
current underlying mechanisms while making it so that people typically
don't need to interact with them. I suspect that those means will
probably take the form of stdlib/builtin support (decorators, custom
base classes, etc) but the design will need some thrashing out. Beyond
that, I don't really have much more to add until I've done some
research into the current state of the art, in the form of libraries
like attrs (and Stephan Hoyer mentioned typing.NamedTuple).

Paul
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-28 Thread Chris Angelico
On Sat, Apr 29, 2017 at 1:31 AM, Steven D'Aprano  wrote:
> On Fri, Apr 28, 2017 at 05:23:59PM +1000, Chris Angelico wrote:
> __init__ is called, the argument 42 is bound to the formal parameter
> "attr", the assignment self.attr = attr is run, and THEN the body of the
> method is called. (Before you object, see below for justification for
> why there has to be both a local variable and an attribute.)
>
> If there is an exception, what do you think the stack trace will point
> to? It cannot point to a line of source code that says "self.attr =
> attr", because there is no such line. At best, it can point to the
> declaration "def __init__(self, self.attr):" although it might not even
> do that.

I don't see why it couldn't. You'll get an AttributeError trying to
set "attr", or maybe it'll be an error from inside __setattr__, but
either way, it's going to come from the 'def' line.

>> > Why should it be defined in terms of general assignment? That's the
>> > point I'm making. While function sigs are a form of assignment, they're
>> > more of a declaration than an executable statement like the other
>> > binding statements. There's a superficial connection, but they really
>> > are quite different things.
>>
>> There's a lot more similarities than you might think. For example,
>> both of these will create "spam" as a local name, shadowing the
>> global:
>>
>> spam = 1
>> def func1(spam):
>> print(spam)
>> def func2():
>> spam = 2
>> print(spam)
>
> Right. Function parameters are local variables. But you can't write:
>
> def func(global spam):
>
> to make it assign to a global instead of a local, or nonlocal, and you
> can't (currently) write:
>
> def func(math.spam):
>
> to make it assign to an attribute of the math module. It's a big
> conceptual leap to go from "formal parameters are always bound to local
> variables of the function" to "formal parameters of the function are
> bound to anything, anywhere".
>
> I wonder whether any other language allows this?

It's a big conceptual leap to go from "iteration steps through a
sequence, binding a variable to successive items in it" to the full
flexibility of Python's for loop. Just look at this:

for idx, val in enumerate(iterable):

It's completely intuitive to an expert Python programmer because it's
a common idiom, but think about it. Firstly, you create an iterable as
a derivative of another iterable. We're building not just lists out of
lists, but lazy iterables out of each other. And that iterable yields
two-item tuples. Finally, we do an unpacking assignment, stashing the
two items into two separate names. And nobody is suggesting that we
should restrict this syntax to simple examples like this; there is
absolutely nothing wrong with having incredibly complicated and
ridiculous assignments inside a for loop. Why? Because a for loop does
simple assignment, nothing more, nothing less.

>> As will many other forms of assignment, like "import spam" or "with x
>> as spam:". Some forms are more restricted than others ("import"
>> requires a NAME, not an arbitrary expression),
>
> Yes, we could restrict the syntax to simple identifiers with a maximum
> of a single dot:
>
> def __init__(self, self.attr,   # allowed
>self[0].foo(1)['key'],  # SyntaxError
>):
>
> which will avoid the worst of the horrors.

Yeah. In that sense, it actually is more like decorator syntax, which
is defined as a strict subset of expression syntax - you have an
absolute guarantee that any legal decorator is semantically equivalent
to the same expression elsewhere, but there are lots of expressions
that you can't use in a decorator. I'd be fine with that. It's still
defined in terms of assignment, but your example would indeed give a
SyntaxError.

>> > You need to speak to more beginners if you think the connection between
>> > spam.x and x is obvious:
>> >
>> > def func(spam.x):
>> > print(x)
>> >
>> > Where is x declared? It looks like there's a local spam.x which isn't
>> > used, and a global x that is. But that's completely wrong. Without the
>> > context of somebody telling you "this is syntax for magically assigning
>> > to self.attributes in the constructor", I believe this will be
>> > unfathomable to the average non-expert.
>>
>> Not sure what you mean. By my reading, that's exactly correct - there
>> IS a global x that is being used here,
>
> No there isn't. "x" is the parameter name, even though it is written
> with a "spam." prefix. Let's go back to the original:
>
> class MyClass:
> def __init__(self, self.attr):
> ...
>
> instance = MyClass(42)
>
> That binds 42 to the local variable "attr", as well as doing the
> self.attr=attr assignment. After all, surely we want to be able to refer
> to the parameter by its local variable, for efficiency (avoiding
> redundant look-ups of self), or to by-pass any __getattr__ on self.

Waait. Why? If you're slapping it in 

Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-28 Thread Stephan Hoyer
On Fri, Apr 28, 2017 at 4:55 AM, Tin Tvrtković  wrote:

> I'm going to posit we need declarative classes. (This is what a library
> like attrs provides, basically.) For a class to be declarative, it needs to
> be possible to inspect the class for its attributes and more.
>

> I'm putting forward three examples. These examples are based on attrs
> since that's what I consider to be the best way of having declarative
> classes in Python today.
>

My favorite example of declarative classes in Python today is Python
3.6.1's typing.NamedTuple:

class Employee(NamedTuple):
"""Represents an employee."""
name: str
id: int = 3

NamedTuple fixes many of the warts of the original namedtuple:
1. It supports docstrings out of the box, not requiring a subclass (which
require setting __slots__ to get right)
2. It supports default values.
3. It has a sane declarative syntax.
4. It's fields can be type checked.

What's not to love? There are two valid complaints [1] about namedtuple
that still apply:
1. It's a tuple, which brings along extra baggage (numeric
indexing/iteration, comparing equal to tuples, etc.)
2. It's immutable. Sometimes it's convenient to have a mutable class.

It seems like a simple solution would be make variants of NamedTuple that
solve each of these issues. We might call these collections.Struct and
collections.FrozenStruct.

[1] e.g., see https://glyph.twistedmatrix.com/2016/08/attrs.html


> Third example: I work at a mobile games company. The backends are Python,
> the games are written in other languages. The backends and the games share
> data structures - requests, responses, the save game, game data. I want to
> have a single source of truth for these structures, so I want to generate
> classes/structs in other languages from the backend Python classes.
>

If you're willing to define these classes outside of Python in a separate
file (which is quite reasonable if you need cross-language support), then
this is exactly the problem solved by protocol buffers (
https://developers.google.com/protocol-buffers/). So I'm not sure we really
need this fix in Python.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-28 Thread Steven D'Aprano
On Fri, Apr 28, 2017 at 05:23:59PM +1000, Chris Angelico wrote:

> Waait a minute. Since when is the *declaration* doing this? 

That's what the suggested syntax says. You put the attribute assignment 
you want in the parameter list, which is part of the function/method 
declaration, not the body. If I recall correctly, the proposal was 
exactly:

def __init__(self, self.attr):

That's not in the body of the function, it's in the parameter list, 
hence part of the declaration. When you call the constructor:

instance = MyClass(42)

__init__ is called, the argument 42 is bound to the formal parameter 
"attr", the assignment self.attr = attr is run, and THEN the body of the 
method is called. (Before you object, see below for justification for 
why there has to be both a local variable and an attribute.)

If there is an exception, what do you think the stack trace will point 
to? It cannot point to a line of source code that says "self.attr = 
attr", because there is no such line. At best, it can point to the 
declaration "def __init__(self, self.attr):" although it might not even 
do that.


> No no no. In every proposal, it's been a part of the function's *execution*.

I did explicitly state that the attribute assignment doesn't occur until 
the function is called, so I'm aware of this. Nevertheless, the source 
code being executed at function call time does not reside in the body of 
the function, but in the function signature.

Maybe I'd be less disturbed by this if we had late binding of defaults 
(defaults are re-evaluated each time they are needed), and a history of 
abusing that for the side-effects:

def function(a, b=print("using b default") or default):

But Python function defaults are early binding, and they're only 
evaluated once, so there's currently no analogy to this proposal.


[...]
> > Why should it be defined in terms of general assignment? That's the
> > point I'm making. While function sigs are a form of assignment, they're
> > more of a declaration than an executable statement like the other
> > binding statements. There's a superficial connection, but they really
> > are quite different things.
> 
> There's a lot more similarities than you might think. For example,
> both of these will create "spam" as a local name, shadowing the
> global:
> 
> spam = 1
> def func1(spam):
> print(spam)
> def func2():
> spam = 2
> print(spam)

Right. Function parameters are local variables. But you can't write:

def func(global spam):

to make it assign to a global instead of a local, or nonlocal, and you 
can't (currently) write:

def func(math.spam):

to make it assign to an attribute of the math module. It's a big 
conceptual leap to go from "formal parameters are always bound to local 
variables of the function" to "formal parameters of the function are 
bound to anything, anywhere".

I wonder whether any other language allows this?


> As will many other forms of assignment, like "import spam" or "with x
> as spam:". Some forms are more restricted than others ("import"
> requires a NAME, not an arbitrary expression), 

Yes, we could restrict the syntax to simple identifiers with a maximum 
of a single dot:

def __init__(self, self.attr,   # allowed
   self[0].foo(1)['key'],  # SyntaxError
   ):

which will avoid the worst of the horrors.


[...]
> > You need to speak to more beginners if you think the connection between
> > spam.x and x is obvious:
> >
> > def func(spam.x):
> > print(x)
> >
> > Where is x declared? It looks like there's a local spam.x which isn't
> > used, and a global x that is. But that's completely wrong. Without the
> > context of somebody telling you "this is syntax for magically assigning
> > to self.attributes in the constructor", I believe this will be
> > unfathomable to the average non-expert.
> 
> Not sure what you mean. By my reading, that's exactly correct - there
> IS a global x that is being used here, 

No there isn't. "x" is the parameter name, even though it is written 
with a "spam." prefix. Let's go back to the original:

class MyClass:
def __init__(self, self.attr):
...

instance = MyClass(42)

That binds 42 to the local variable "attr", as well as doing the 
self.attr=attr assignment. After all, surely we want to be able to refer 
to the parameter by its local variable, for efficiency (avoiding 
redundant look-ups of self), or to by-pass any __getattr__ on self.

Or to really push the message, think about calling it by keyword:

instance = MyClass(self.attr=42)  # No.
instance = MyClass(attr=42)  # Yes.

In other words, even though the formal parameter is written as 
"self.attr", the argument is bound to the local "attr".

Quite frankly, I thought this was so self-evident that it didn't even 
occur to me that anyone would have imagined that no local variable 
"attr" would be created. As weird as it is to have a parameter declared 
as "self.attr" but bound to "attr", 

Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-28 Thread Nick Coghlan
On 28 April 2017 at 22:26, Paul Moore  wrote:
> On 28 April 2017 at 12:55, Tin Tvrtković  wrote:
>> I'm putting forward three examples. These examples are based on attrs since
>> that's what I consider to be the best way of having declarative classes in
>> Python today.
>
> Your comments and examples are interesting, but don't they just come
> down to "attrs is a really good library"? I certainly intend to look
> at it based on what's been said in this thread. But I don't see
> anything much that suggests that anything *beyond* attrs is needed
> (except maybe bringing attrs into the stdlib, if its release cycle
> would make that reasonable and the author was interested, and honestly
> "put it in the stdlib" could be said about any good library - in
> practice though publishing on PyPI and accessing via pip is 99% of the
> time the more reasonable option).
>
> Am I missing some point?

Yes, the point I attempted to raise earlier: at the language design
level, "How do we make __init__ methods easier to write?" is the
*wrong question* to be asking. It's treating the symptom (writing an
imperative initialiser is repetitive when it comes to field names)
rather than the root cause (writing imperative initialisers is still
part of the baseline recommendation for writing classes, and we don't
offer any supporting infrastructure for avoiding that directly in the
standard library)

Accordingly, a potentially better question to ask is "How do we make
it so that writing a custom __init__ method for each class definition
seems as strange and esoteric in 2025 as writing a custom metaclass
seems now?".

For a *lot* of classes, what we want to be able to define is:

- a set of data fields
- a basic initialiser to set those fields by name
- a repr based on those fields (or a subset)
- equality comparisons based on those fields (or a subset)
- ordering comparisons based on those fields (or a subset)
- conversion to a JSON-friendly dict
- pickling support
- copying support

Given the initial set of data fields, reasonable default behaviours
for all of the rest can be derived automatically, but we don't provide
the tools to do that derivation by default. This leaves teachers of
Python in a quandary: they can either teach "native Python classes"
(which are boilerplate heavy and error prone), or else they can pick a
third party library like attrs, and teach "Python-with-attrs", in the
same way that it's recommended to teach "Python-with-requests" rather
than the native urllib APIs when it comes to accessing resources over
HTTPS.

The difference between this case and requests is that HTTPS and
related protocols experience a high level of churn independently of
Python language updates, so there are real logistical benefits to
maintaining it as a third party module.

By contrast, if we add an "autoclass" module to the standard library
that adds more tools like functools.total_ordering to handle injecting
boilerplate functionality into class definitions at runtime, then
that's a pure win - folks can either delegate the details of their
instance behaviour to the standard library maintainers (in the same
way that most folks already delegate the behaviour of their
metaclasses), or else they can continue to write out all those
supported methods by hand if they really want or need the fine-grained
control.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-28 Thread Nick Coghlan
On 28 April 2017 at 21:55, Tin Tvrtković  wrote:
> Third example: I work at a mobile games company. The backends are Python,
> the games are written in other languages. The backends and the games share
> data structures - requests, responses, the save game, game data. I want to
> have a single source of truth for these structures, so I want to generate
> classes/structs in other languages from the backend Python classes.

Some additional metaclass based prior art for declarative class definitions:

- Django ORM models
- SQL Alchemy ORM models
- JSL template definitions (http://jsl.readthedocs.io/en/latest/tutorial.html)

(I'm sure there's also plenty of prior art in Zope and Plone, but I'm
not personally all that familiar with either of those)

> All of these examples require declarative classes to do properly. Other
> approaches are, I suppose, possible in some cases - like inspecting __init__
> and whatnot. But I claim the underlying issue is that we should be declaring
> classes differently, both to enable these new, high-level use cases and
> because declarative classes are much more readable and contain less
> boilerplate than what we have now, and this is (for me) Python is about.

Exactly.

I don't think we should change anything about the basic semantics of
class or method definitions (since they're part of what makes it
possible to reason about Python as an inherently procedural language),
but I *do* think we should be considering the kinds of helpers we can
provide as class decorators to take the boilerplate and tedium out of
defining well-behaved classes.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-28 Thread Paul Moore
On 28 April 2017 at 12:55, Tin Tvrtković  wrote:
> I'm putting forward three examples. These examples are based on attrs since
> that's what I consider to be the best way of having declarative classes in
> Python today.

Your comments and examples are interesting, but don't they just come
down to "attrs is a really good library"? I certainly intend to look
at it based on what's been said in this thread. But I don't see
anything much that suggests that anything *beyond* attrs is needed
(except maybe bringing attrs into the stdlib, if its release cycle
would make that reasonable and the author was interested, and honestly
"put it in the stdlib" could be said about any good library - in
practice though publishing on PyPI and accessing via pip is 99% of the
time the more reasonable option).

Am I missing some point?
Paul
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-28 Thread Tin Tvrtković
I'm gonna take a shot at elaborating this point.

We Python programmers often tout Python as a high-level, high-productivity
language where complex and useful things are easy to do. However, vanilla
Python classes are anything but high level; they're basically glorified
dictionaries that require an awful lot of boilerplate for basic features.
__init__ verbosity is just one of the symptoms of this.

I'm going to posit we need declarative classes. (This is what a library
like attrs provides, basically.) For a class to be declarative, it needs to
be possible to inspect the class for its attributes and more.

I'm putting forward three examples. These examples are based on attrs since
that's what I consider to be the best way of having declarative classes in
Python today.

First example. Here's a slide from a recent talk I've given to a local
Python meetup: http://tinche.github.io/talks/attrs/#/8/5 This is a class
decorator that, when applied to any attrs class, will generate a simple
shallow copy() method for that class. This copy method will be faster than
copy.copy() and IMO less surprising since it will actually invoke __init__
(and all logic inside). This isn't production code, just a proof of concept
for the talk.

Second example: I'm working on a library that can turn dictionaries into
attrs classes (i.e. turn unstructured data into structured data). Example:
http://cattrs.readthedocs.io/en/latest/structuring.html#attrs-classes. When
dealing with nested classes the library not only needs to know exactly
which fields a class has but also the types of those fields, recursively
(for which I'm planning to use attrs metadata). This functionality is
useful when preparing data to be stored or sent elsewhere, since
serialization libraries and clients in other languages expect json/msgpack
etc.

Third example: I work at a mobile games company. The backends are Python,
the games are written in other languages. The backends and the games share
data structures - requests, responses, the save game, game data. I want to
have a single source of truth for these structures, so I want to generate
classes/structs in other languages from the backend Python classes.

All of these examples require declarative classes to do properly. Other
approaches are, I suppose, possible in some cases - like inspecting
__init__ and whatnot. But I claim the underlying issue is that we should be
declaring classes differently, both to enable these new, high-level use
cases and because declarative classes are much more readable and contain
less boilerplate than what we have now, and this is (for me) Python is
about.

Message: 1
> Date: Fri, 28 Apr 2017 09:28:55 +1000
> From: Steven D'Aprano <st...@pearwood.info>
> To: python-ideas@python.org
> Subject: Re: [Python-ideas] Augmented assignment syntax for objects.
> Message-ID: <20170427232853.gc22...@ando.pearwood.info>
> Content-Type: text/plain; charset=iso-8859-1
>
> On Wed, Apr 26, 2017 at 08:52:46PM -0400, Juancarlo A?ez wrote:
>
> > In my experience, what Python is lacking is a way to declare attributes
> > outside of the constructor. Take a look at how it's done in C#, Swisft,
> or
> > Go.
>
> Since you apparently already know how they do it, how about telling us
> (1) how they do it, and (2) *why* they do it?
>
>
> > Object attributes outside of the constructor would solve things more
> > relevant than the vertical space used when assigning constructor
> parameters
> > to attributes.
>
> Solve which things?
>
>
> > For example, multiple inheritance is well designed in
> > Python, except that it often requires constructors with no parameters,
> > which leads to objects with no default attributes.
>
> Can you elaborate?
>
>
>
> --
> Steve
>
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-28 Thread Steven D'Aprano
On Fri, Apr 28, 2017 at 03:30:29PM +1000, Chris Angelico wrote:

> > Obviously we can define syntax to do anything we like, but what is the
> > logical connection between the syntax and the semantics? What part of
> > "function parameter list" suggests "assign attributes to arbitrary
> > objects"?
[...]
> What part of a 'for' loop suggests that you can do this?

I'm not sure what "this" is supposed to do. You've written some 
obscure but perfectly legal Python code:

> odds = [0]*10; evens = [0]*10
> for idx, (odds if idx%2 else evens)[idx//2] in stuff:
> ...

My guess is that "this" refers to the side-effect that assigning to a 
list item updates the list item. Um, yeah, it does. What's your point? 
Of course it does. That's what its supposed to do.

Perhaps you think that there's something weird about using an arbitrary 
assignment target as the for-loop. I don't know why you think that's 
weird. Here's a simpler example:

for obj.attr in seq:
...

Yes, its a bit unusual to do that, but its not weird. The assignment 
target for a loop is just an ordinary assignment target, and the 
assignment occurs during the execution of code, just like any other 
assignment that occurs inside the body of the function.

What is weird is to have the function *declaration* have global side 
effects and perform assignments outside of the function. The parameter 
list is *not* a general assignment statement, it is a declaration of 
what local variables will be assigned to when you call the function.

In Python 3, function paramaters are plain (non-qualified) 
identifiers, not general assignment targets. Even in Python 2, the most 
that was supported were tuple-unpacking. Even that can be read as 
conceptually just a declaration:

def func(a, (x,y)):

declares that the first argument is a, and the second argument is a pair 
of values x and y. But this proposal has to be read as a declaration 
plus a separate assignment:

def func(a, spam.x):

declares that the second argument is called "x", (but not spam.x), and 
*in addition* there will be an assignment spam.x = x at some point, 
presumably before the function body gets entered.


> Nothing whatsoever says that this is a good idea, but it's perfectly
> legal, because the for loop is defined in terms of assignment. If this
> were to be accepted (which, fwiw, I'm not actually advocating, but
> IF), it would also be defined in terms of assignment.

Why should it be defined in terms of general assignment? That's the 
point I'm making. While function sigs are a form of assignment, they're 
more of a declaration than an executable statement like the other 
binding statements. There's a superficial connection, but they really 
are quite different things.

(For example: if you allow spam.foo as a parameter, that can call 
arbitrary Python code in spam.__setattr__, which assigning to foo as a 
parameter will not do.)


> You still
> shouldn't be assigning to arbitrary objects, especially not randomly
> rebinding module names, but it's easy to grok the assignment
> equivalence.

You need to speak to more beginners if you think the connection between 
spam.x and x is obvious:

def func(spam.x):
print(x)

Where is x declared? It looks like there's a local spam.x which isn't 
used, and a global x that is. But that's completely wrong. Without the 
context of somebody telling you "this is syntax for magically assigning 
to self.attributes in the constructor", I believe this will be 
unfathomable to the average non-expert.


> And yes, it WOULD reinstate the argument unpacking removed by PEP
> 3113. So for this to go forward, the objections in that PEP would have
> to be addressed.

Nicely remembered :-)



-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-27 Thread Chris Angelico
On Fri, Apr 28, 2017 at 2:06 PM, Steven D'Aprano  wrote:
> On Fri, Apr 28, 2017 at 09:54:55AM +1000, Chris Angelico wrote:
>> On Fri, Apr 28, 2017 at 9:21 AM, Steven D'Aprano  wrote:
>> > What happens if you use this syntax in a top-level function rather
>> > than a method? (Or a static method?)
>> >
>> > def function(x, y, x.attr):
>> > ...
>> >
>> > (And don't forget that behind the scenes, methods *are* functions.) What
>> > would this syntax even mean?
>> >
>> >
>> > Or if you use some other name other than the first parameter?
>> >
>> > def method(self, spam, foo.eggs):
>>
>> Exactly the same thing as:
>>
>> def function(*args):
>> x, y, x.attr = args
>>
>> def method(*args):
>> self, spam, foo.eggs = args
>
>
> Obviously we can define syntax to do anything we like, but what is the
> logical connection between the syntax and the semantics? What part of
> "function parameter list" suggests "assign attributes to arbitrary
> objects"?
>
> Do we support arbitrary targets in their full generality?
>
> def function(arg,
> (name if name is not None else 
> other).the_object.attr[0].method(foo)['key'].argument
> ):
> ...
>
> Of course, there are lots of things which are technically allowed but if
> someone is silly enough to do it, we say "don't do that". However, even
> the simple case is problematic:
>
> def trigonometry(x, y, math.pi)
>
> We could make that parameter declaration have the side-effect of
> assigning to math.pi, but that's a pretty surprising change to function
> declarations. Everything else declared inside a parameter list is local
> to the function: parameters themselves are local variables, default
> values and annotations are stored in the function not externally.

What part of a 'for' loop suggests that you can do this?

odds = [0]*10; evens = [0]*10
for idx, (odds if idx%2 else evens)[idx//2] in stuff:
...

Nothing whatsoever says that this is a good idea, but it's perfectly
legal, because the for loop is defined in terms of assignment. If this
were to be accepted (which, fwiw, I'm not actually advocating, but
IF), it would also be defined in terms of assignment. You still
shouldn't be assigning to arbitrary objects, especially not randomly
rebinding module names, but it's easy to grok the assignment
equivalence.

And yes, it WOULD reinstate the argument unpacking removed by PEP
3113. So for this to go forward, the objections in that PEP would have
to be addressed.

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-27 Thread Steven D'Aprano
On Fri, Apr 28, 2017 at 09:54:55AM +1000, Chris Angelico wrote:
> On Fri, Apr 28, 2017 at 9:21 AM, Steven D'Aprano  wrote:
> > What happens if you use this syntax in a top-level function rather
> > than a method? (Or a static method?)
> >
> > def function(x, y, x.attr):
> > ...
> >
> > (And don't forget that behind the scenes, methods *are* functions.) What
> > would this syntax even mean?
> >
> >
> > Or if you use some other name other than the first parameter?
> >
> > def method(self, spam, foo.eggs):
> 
> Exactly the same thing as:
> 
> def function(*args):
> x, y, x.attr = args
> 
> def method(*args):
> self, spam, foo.eggs = args


Obviously we can define syntax to do anything we like, but what is the 
logical connection between the syntax and the semantics? What part of 
"function parameter list" suggests "assign attributes to arbitrary 
objects"?

Do we support arbitrary targets in their full generality?

def function(arg, 
(name if name is not None else 
other).the_object.attr[0].method(foo)['key'].argument
):
...

Of course, there are lots of things which are technically allowed but if 
someone is silly enough to do it, we say "don't do that". However, even 
the simple case is problematic:

def trigonometry(x, y, math.pi)

We could make that parameter declaration have the side-effect of 
assigning to math.pi, but that's a pretty surprising change to function 
declarations. Everything else declared inside a parameter list is local 
to the function: parameters themselves are local variables, default 
values and annotations are stored in the function not externally.

The only thing which is not local is that default values may be 
arbitrary expressions, which may have side-effects, but that is not a 
declaration, its an expression evaluated for its value.

What's the connection between parameter declarations and this sort of 
external side-effect? It seems pretty arbitrary to be a built-in part of 
the language, like having

def function(x)

automatically print x, or pickle it and upload the file to the cloud.

(Obviously the side-effect doesn't occur until the function is called, 
but still, it is part of the parameter list declaration, not the body of 
the function.)

I have grave doubts that people will find this obvious, let alone 
useful. Having a function declaration, the parameter list, have 
side-effects outside of the function seems like both a surprising and a 
bad idea to me.


> It's well-defined - at least for positional args. Not sure what
> keyword arg handling would be though.

Why would it be any different? If it makes sense to allow:

def function(spam, eggs, something.foo)

assign to something.foo, then why should it matter whether it was called 
by keyword or positional? Or declared as keyword only?

def function(spam, eggs, *, something.cheese)


I don't think it makes sense either way, but it isn't because it is a 
keyword arg. I think it is arbitrarily mixing two distinct things into 
one convenient but confusing syntax.

function(spam=1, eggs=2, something.cheese=3)  # won't work



-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-27 Thread Steven D'Aprano
On Wed, Apr 26, 2017 at 08:02:39AM -0400, tritium-l...@sdamon.com wrote:

> > self.__dict__.update(kwargs)
> 
> Touching __dict__ feels dirty to me.


Indeed. The right way is:

vars(self).update(kwargs)

although that doesn't work if self is written to use __slots__ instead 
of having a __dict__.

You can even (almost) get this same effect and still have named 
parameters:

def __init__(self, fe, fi, fo, fum, spam, eggs, foo, bar, baz):
vars(self).update(locals())
del self.self


-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-27 Thread Steven D'Aprano
On Wed, Apr 26, 2017 at 08:52:46PM -0400, Juancarlo Añez wrote:

> In my experience, what Python is lacking is a way to declare attributes
> outside of the constructor. Take a look at how it's done in C#, Swisft, or
> Go.

Since you apparently already know how they do it, how about telling us 
(1) how they do it, and (2) *why* they do it?


> Object attributes outside of the constructor would solve things more
> relevant than the vertical space used when assigning constructor parameters
> to attributes. 

Solve which things?


> For example, multiple inheritance is well designed in
> Python, except that it often requires constructors with no parameters,
> which leads to objects with no default attributes.

Can you elaborate?



-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-27 Thread Steven D'Aprano
On Wed, Apr 26, 2017 at 03:54:22PM -0400, Jerry Hill wrote:
> On Tue, Apr 25, 2017 at 8:05 PM, Ryan Gonzalez  wrote:
> > def ___init__(self, self.attr):
> 
> I'm not a python developer, I'm just a developer that uses python.
> That said, I really like this form.  It eliminates most of the
> redundancy, while still being explicit.  It's true that you have to
> repeat the 'self' name, but it feels like the right balance in my
> mind.  It seems like anyone who's familiar with python function
> definitions would immediately grasp what's going on.

I don't like it, not even a bit. It's not general, "self" is effectively 
a special case. Consider:

What happens if you use this syntax in a top-level function rather 
than a method? (Or a static method?)

def function(x, y, x.attr):
...

(And don't forget that behind the scenes, methods *are* functions.) What 
would this syntax even mean? 


Or if you use some other name other than the first parameter?

def method(self, spam, foo.eggs):
...


Conceptually, it is mixing up two distinct tasks:

- declaring the parameter list of the function/method;

- running part of the body of the method.

The parameter list of the method is the *interface* to the method: it 
tells you the public names and default values (and possibly types, if 
you use type annotations) of the method parameters. But this syntax 
overloads the parameter list to show part of the *implementation* of the 
method (namely, that some parameters are assigned directly to attributes 
of self). Every time the implementation changes, the parameter list will 
change too.

For instance, if you decide to add some argument validation to your 
arguments (checking that their values and types are correct), using the 
self.attr form is inappropriate.

And while it looks okay in the toy example shown by Ryan:

def ___init__(self, self.attr):


it doesn't look so good in larger, more realistic cases, especially with 
other syntax. Here's a parameter list taken from some real code of mine, 
with the "self." syntax added:


class BinnedData(object):
def __init__(self, self.number:int, 
   self.start:float=None, 
   self.end:float=None, 
   self.width:float=None, 
   *, 
   self.policy=None, 
   self.mark=False
   ):

The repetition of "self" is not only tedious and verbose, it adds 
noise to the parameter list and pushes the reader's attention away from 
the important part (the name of the parameter, e.g. "width") and to 
something irrelevant to the interface ("self").

And I am not looking forward to having to explain to beginners to Python 
why this doesn't work:

data = BinnedData(self.number = 8, self.start = 0, self.end = 20)



-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-27 Thread Erik

On 27/04/17 23:43, Steven D'Aprano wrote:

On Wed, Apr 26, 2017 at 11:29:19PM +0100, Erik wrote:

def __init__(self, a, b, c):
   self import a, b
   self.foo = c * 100


[snarky]
If we're going to randomly choose arbitrary keywords with no connection
to the operation being performed,


The keyword I chose was not random or arbitrary and it _does_ have a 
connection to the operation being performed (bind a value in the source 
namespace to the target namespace using the same name it had in the 
source namespace - or rename it using the 'as' keyword).



can we use `del` instead of `import`
because it's three characters less typing?


Comments like this just serve to dismiss or trivialize the discussion. 
We acknowledged that we're bikeshedding so it was not a serious 
suggestion, just a "synapse prodder" ...



But seriously, I hate this idea.


Good. It's not a proposal, but something that was supposed to generate 
constructive discussion.



The semantics are very different and there's little or no connection
between importing a module and setting an attribute on self.


At the technical level of what goes on under the covers, yes. At the 
higher level of what the words mean in spoken English, it's really not 
so different a concept.



If we're going to discuss pie-in-the-sky suggestions,


That is just dismissing/trivializing the conversation again.


(If you don't like "inject", I'm okay with "load" or even "push".)


No you're not, because that's a new keyword which might break existing 
code and that is even harder to justify than re-using an existing 
keyword in a different context.



the problem this solves isn't big or
important enough for the disruption of adding a new keyword.


So far, you are the only one to have suggested adding a new keyword, I 
think ;)


E.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-27 Thread Steven D'Aprano
On Wed, Apr 26, 2017 at 11:29:19PM +0100, Erik wrote:

> But, if we're going to bikeshed and there is some weight behind the idea 
> that this "papercut" should be addressed, then given my previous 
> comparisons with importing, what about having 'import' as an operator:
> 
> def __init__(self, a, b, c):
>self import a, b
>self.foo = c * 100

[snarky]
If we're going to randomly choose arbitrary keywords with no connection 
to the operation being performed, can we use `del` instead of `import` 
because it's three characters less typing?
[/snarky]

*wink*

But seriously, I hate this idea. `import` has certain semantics that 
don't apply here:

- import goes through the full import system (sys.modules, reading 
  files from disk, sys.path, etc.); this "self import ..." does not;

- import creates local variables; this "self import ..." does not.

The semantics are very different and there's little or no connection 
between importing a module and setting an attribute on self.

If we're going to discuss pie-in-the-sky suggestions, here is an only 
semi-serious suggestion. A statement that injects identifiers into 
an explicitly given name space:

inject spam, eggs as cackleberry, cheese into self

(If you don't like "inject", I'm okay with "load" or even "push".)

This would be equivalent to:

self.spam = spam
self.cackleberry = eggs
self.cheese = cheese

Presumably it would be implemented a little more efficiently, e.g. only 
a single lookup for self, etc. Note that the target is completely 
general: you can inject into any object which will accept setting 
attributes:

inject spam, eggs into namespace

If the "inject as" form is used, the value can be any expression:

inject x + 1 as y into namespace

otherwise the value must be a valid identifier but not necessarily a 
local variable.

If I were designing a language from scratch, one with a maximalist 
approach to syntax, I'd take this seriously. But Python has relatively 
minimal syntax and keywords, and the problem this solves isn't big or 
important enough for the disruption of adding a new keyword.



-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-27 Thread Sven R. Kunze

On 26.04.2017 23:50, Mark Lawrence via Python-ideas wrote:

On 26/04/2017 21:50, Chris Angelico wrote:

On Thu, Apr 27, 2017 at 6:24 AM, Erik  wrote:

The background is that what I find myself doing a lot of for private
projects is importing data from databases into a structured 
collection of
objects and then grouping and analyzing the data in different ways 
before

graphing the results.

So yes, I tend to have classes that accept their entire object state as
parameters to the __init__ method (from the database values) and 
then any
other methods in the class are generally to do with the subsequent 
analysis

(including dunder methods for iteration, rendering and comparison etc).


You may want to try designing your objects as namedtuples. That gives
you a lot of what you're looking for.

ChrisA



Something like 
https://docs.python.org/3/library/sqlite3.html#row-objects ?




Or something like https://docs.djangoproject.com/en/1.11/topics/db/models/

Sven
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-27 Thread Ryan Gonzalez
*cough* I'll just drop this here a sec *cough*:

https://code.activestate.com/recipes/580790-auto-assign-self-attributes-in-__init__-using-pep-/

On Thu, Apr 27, 2017 at 10:24 AM, Nick Coghlan  wrote:
> On 25 April 2017 at 11:08, Erik  wrote:
>> Hi. I suspect that this may have been discussed to death at some point in
>> the past, but I've done some searching and I didn't come up with much.
>
> Hi Erik,
>
> Offering more concise ways of writing more powerful class definitions
> is certainly a common topic of exploration in Python development.
>
> A couple of folks have already mentioned Hynek Schlawack's `attrs`
> packages, which pairs up a class decorator with particular kinds of
> values set as class level attributes:
>
> from attr import attrs, attrib
>
> @attrs
> class MyClass:
> foo = attrib()
> bar = attrib()
> baz = attrib()
> ...
>
> Here, the `attrs` decorator not only writes __init__ for you, but also
> __repr__, comparison operators, pickle support, and a range of other
> things. Glyph Lefkowitz put together a good post last year describing
> just how much functionality attrs implicitly adds to a typical class
> definition, all while making it shorter and less repetitive:
> https://glyph.twistedmatrix.com/2016/08/attrs.html
>
> So I think if Python were to make any changes to the default toolset
> in this area, it would be more along the lines of how `attrs` works
> (i.e. offering a more declarative approach to the high level task of
> defining structured data containers), than it would be along the lines
> of a low level syntactic solution that only benefited `__init__` and
> `__new__` without addressing any of the other repetitive aspects of
> writing comprehensive class definitions.
>
> For example, if we decided we wanted to go down that path, we could
> add a new `autoclass` module and write the equivalent of the above as:
>
> from autoclass import make, field
>
> @make
> class MyClass:
> foo = field()
> bar = field()
> baz = field()
> ...
>
> That would provide us with a clear terminological distinction between
> autoclass fields and class attributes in general, while still letting
> people eliminate a lot of the boilerplate currently involved in
> writing classes that produce nice and easy to use instances.
>
> Cheers,
> Nick.
>
> --
> Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/



-- 
Ryan (ライアン)
Yoko Shimomura > ryo (supercell/EGOIST) > Hiroyuki Sawano >> everyone else
http://refi64.com/
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-27 Thread Nick Coghlan
On 25 April 2017 at 11:08, Erik  wrote:
> Hi. I suspect that this may have been discussed to death at some point in
> the past, but I've done some searching and I didn't come up with much.

Hi Erik,

Offering more concise ways of writing more powerful class definitions
is certainly a common topic of exploration in Python development.

A couple of folks have already mentioned Hynek Schlawack's `attrs`
packages, which pairs up a class decorator with particular kinds of
values set as class level attributes:

from attr import attrs, attrib

@attrs
class MyClass:
foo = attrib()
bar = attrib()
baz = attrib()
...

Here, the `attrs` decorator not only writes __init__ for you, but also
__repr__, comparison operators, pickle support, and a range of other
things. Glyph Lefkowitz put together a good post last year describing
just how much functionality attrs implicitly adds to a typical class
definition, all while making it shorter and less repetitive:
https://glyph.twistedmatrix.com/2016/08/attrs.html

So I think if Python were to make any changes to the default toolset
in this area, it would be more along the lines of how `attrs` works
(i.e. offering a more declarative approach to the high level task of
defining structured data containers), than it would be along the lines
of a low level syntactic solution that only benefited `__init__` and
`__new__` without addressing any of the other repetitive aspects of
writing comprehensive class definitions.

For example, if we decided we wanted to go down that path, we could
add a new `autoclass` module and write the equivalent of the above as:

from autoclass import make, field

@make
class MyClass:
foo = field()
bar = field()
baz = field()
...

That would provide us with a clear terminological distinction between
autoclass fields and class attributes in general, while still letting
people eliminate a lot of the boilerplate currently involved in
writing classes that produce nice and easy to use instances.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread MRAB

On 2017-04-26 23:29, Erik wrote:

On 26/04/17 19:15, Mike Miller wrote:

As the new syntax ideas piggyback on existing syntax, it doesn't feel
like that its a complete impossibility to have this solved.  Could be
another "fixed papercut" to drive Py3 adoption.  Taken individually not
a big deal but they add up.


*sigh* OK, this has occurred to me over the last couple of days but I
didn't want to suggest it as I didn't want the discussion to fragment
even more.

But, if we're going to bikeshed and there is some weight behind the idea
that this "papercut" should be addressed, then given my previous
comparisons with importing, what about having 'import' as an operator:

def __init__(self, a, b, c):
 self import a, b
 self.foo = c * 100

Also allows renaming:

def __init__(self, a, b, c):
 self import a, b, c as _c

Because people are conditioned to think the comma-separated values after
"import" are not tuples, perhaps the use of import as an operator rides
on that wave ...

(I do realise that blurring the lines between statements and operators
like this is probably not going to work for technical reasons (and it
just doesn't quite read correctly anyway), but now we're bikeshedding
and who knows what someone else might come up with in response ...).


If we're going to bikeshed, then:

def __init__(self, a, b, c):
for self import a, b
self.foo = c * 100

and:

def __init__(self, a, b, c):
for self import a, b, c as _c
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Juancarlo Añez
On Wed, Apr 26, 2017 at 6:57 PM, Mike Miller 
wrote:

> Yes, I like it too.  Removes the triple repetition, and has precedent in
> the other languages.


This discussion has been around how to deal with repetition in object
constructors, and the proposals have been a new assignment statement (patch
assignments?) or decorators to __init__ (patch init).

In my experience, what Python is lacking is a way to declare attributes
outside of the constructor. Take a look at how it's done in C#, Swisft, or
Go.

Object attributes outside of the constructor would solve things more
relevant than the vertical space used when assigning constructor parameters
to attributes. For example, multiple inheritance is well designed in
Python, except that it often requires constructors with no parameters,
which leads to objects with no default attributes.

The namespace after "class"  is taken by class attributes. There's no
namespace for default object attributes outside __init__. Solving that
would likely lead to simple and sensible solutions to the OPs query.

I don't think that a solution to the OPs query should be treated as a
No-No, because there's namedtuple, which is quirky, but solved lots of use
cases (the same goes for Enum).

IMHO, something like the attrs library solves lots of common use cases...
except that tool support is poor because attrs is not part of stdlib.

It is not about having to write a few more lines in an __init__
constructor. There are common and frequent use cases of "objects are mostly
data" that are partially solved in Python (mostly through namedtuple?).

Cheers!

-- 
Juancarlo *Añez*
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Mike Miller
Yes, I like it too.  Removes the triple repetition, and has precedent in the 
other languages.



On 2017-04-26 12:54, Jerry Hill wrote:

On Tue, Apr 25, 2017 at 8:05 PM, Ryan Gonzalez  wrote:

def ___init__(self, self.attr):


I'm not a python developer, I'm just a developer that uses python.
That said, I really like this form.  It eliminates most of the
redundancy, while still being explicit.  It's true that you have to
repeat the 'self' name, but it feels like the right balance in my
mind.

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Erik

On 26/04/17 23:28, Paul Moore wrote:

Or to put it another way, if the only
reason for the syntax proposal is performance then show me a case
where performance is so critical that it warrants a language change.


It's the other way around.

The proposal (arguably) makes the code clearer but does not impact 
performance (and is a syntax error today, so does not break existing code).


The suggestions (decorators etc) make the code (arguably) clearer today 
without a syntax change, but impact performance.


So, those who think the decorators make for clearer code have to choose 
between source code clarity and performance.


E.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Erik

On 26/04/17 19:15, Mike Miller wrote:

As the new syntax ideas piggyback on existing syntax, it doesn't feel
like that its a complete impossibility to have this solved.  Could be
another "fixed papercut" to drive Py3 adoption.  Taken individually not
a big deal but they add up.


*sigh* OK, this has occurred to me over the last couple of days but I 
didn't want to suggest it as I didn't want the discussion to fragment 
even more.


But, if we're going to bikeshed and there is some weight behind the idea 
that this "papercut" should be addressed, then given my previous 
comparisons with importing, what about having 'import' as an operator:


def __init__(self, a, b, c):
   self import a, b
   self.foo = c * 100

Also allows renaming:

def __init__(self, a, b, c):
   self import a, b, c as _c

Because people are conditioned to think the comma-separated values after 
"import" are not tuples, perhaps the use of import as an operator rides 
on that wave ...


(I do realise that blurring the lines between statements and operators 
like this is probably not going to work for technical reasons (and it 
just doesn't quite read correctly anyway), but now we're bikeshedding 
and who knows what someone else might come up with in response ...).


E.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Paul Moore
On 26 April 2017 at 22:42, Erik  wrote:
> 2) The original proposal, which does belong on -ideas and has to take into
> account the general case, not just my specific use-case.
>
> The post you are responding to is part of (2), and hence reduced performance
> is a consideration.

Ah, OK. I'm discounting the original proposal, as there don't seem to
be sufficient (i.e., any :-)) actual use cases that aren't covered by
the decorator proposal(s). Or to put it another way, if the only
reason for the syntax proposal is performance then show me a case
where performance is so critical that it warrants a language change.

Sorry for not being clear myself.
Paul
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Mark Lawrence via Python-ideas

On 26/04/2017 21:50, Chris Angelico wrote:

On Thu, Apr 27, 2017 at 6:24 AM, Erik  wrote:

The background is that what I find myself doing a lot of for private
projects is importing data from databases into a structured collection of
objects and then grouping and analyzing the data in different ways before
graphing the results.

So yes, I tend to have classes that accept their entire object state as
parameters to the __init__ method (from the database values) and then any
other methods in the class are generally to do with the subsequent analysis
(including dunder methods for iteration, rendering and comparison etc).


You may want to try designing your objects as namedtuples. That gives
you a lot of what you're looking for.

ChrisA



Something like https://docs.python.org/3/library/sqlite3.html#row-objects ?

--
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Erik

On 26/04/17 22:28, Paul Moore wrote:

On 26 April 2017 at 21:51, Erik  wrote:

It doesn't make anything more efficient, however all of the suggestions of
how to do it with current syntax (mostly decorators) _do_ make things less
efficient.


Is instance creation the performance bottleneck in your application?


No, not at all. This discussion has split into two:

1) How can I personally achieve what I want for my own personal 
use-cases. This should really be on -list, and some variation of the 
decorator thing will probably suffice for me.


2) The original proposal, which does belong on -ideas and has to take 
into account the general case, not just my specific use-case.


The post you are responding to is part of (2), and hence reduced 
performance is a consideration.


Regards, E.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Paul Moore
On 26 April 2017 at 21:51, Erik  wrote:
> It doesn't make anything more efficient, however all of the suggestions of
> how to do it with current syntax (mostly decorators) _do_ make things less
> efficient.

Is instance creation the performance bottleneck in your application?
That seems unusual. I guess it's possible if you're reading a large
database file and creating objects for each row. But in that case, as
Chris A says, you may be better with something like a named tuple. In
any case, optimising for performance is not what generic solutions are
good at, so it's not surprising that a generic decorator involves a
performance hit.

Paul
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Erik

On 26/04/17 01:39, Nathaniel Smith wrote:
[snip discussion of why current augmented assignment operators are 
better for other reasons]



Are there any similar arguments for .=?


It doesn't make anything more efficient, however all of the suggestions 
of how to do it with current syntax (mostly decorators) _do_ make things 
less efficient.


So rather than a win/win as with current augmented assignment 
(compact/clearer code *and* potentially a performance improvement), it's 
now a tradeoff (wordy code *or* a performance reduction).


E.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Chris Angelico
On Thu, Apr 27, 2017 at 6:24 AM, Erik  wrote:
> The background is that what I find myself doing a lot of for private
> projects is importing data from databases into a structured collection of
> objects and then grouping and analyzing the data in different ways before
> graphing the results.
>
> So yes, I tend to have classes that accept their entire object state as
> parameters to the __init__ method (from the database values) and then any
> other methods in the class are generally to do with the subsequent analysis
> (including dunder methods for iteration, rendering and comparison etc).

You may want to try designing your objects as namedtuples. That gives
you a lot of what you're looking for.

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Erik

On 26/04/17 16:10, Nick Timkovich wrote:

I was wondering that if there are so many arguments to a function that
it *looks* ugly, that it might just *be* ugly.

For one, too many required arguments to a function (constructor,
whatever) is already strange. Binding them as attributes of the object,
unmodified in a constructor also seems to be rare.


Yes, and perhaps it's more of a problem for me because of my 
possibly-atypical use of Python.


The background is that what I find myself doing a lot of for private 
projects is importing data from databases into a structured collection 
of objects and then grouping and analyzing the data in different ways 
before graphing the results.


So yes, I tend to have classes that accept their entire object state as 
parameters to the __init__ method (from the database values) and then 
any other methods in the class are generally to do with the subsequent 
analysis (including dunder methods for iteration, rendering and 
comparison etc).


E.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Jerry Hill
On Tue, Apr 25, 2017 at 8:05 PM, Ryan Gonzalez  wrote:
> def ___init__(self, self.attr):

I'm not a python developer, I'm just a developer that uses python.
That said, I really like this form.  It eliminates most of the
redundancy, while still being explicit.  It's true that you have to
repeat the 'self' name, but it feels like the right balance in my
mind.  It seems like anyone who's familiar with python function
definitions would immediately grasp what's going on.

-- 
Jerry
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Erik

On 26/04/17 18:42, Mike Miller wrote:

I want to be able to say:


def __init__(self, foo, bar, baz, spam):
  self .= foo, bar, spam
  self.baz = baz * 100



I don't see ALL being set a big problem, and less work than typing
several of them out again.


Because, some of the parameters might be things that are just passed to 
another constructor to create an object that is then referenced by the 
object being created.


If one doesn't want the object's namespace to be polluted by that stuff 
(which may be large and also now can't be garbage collected while the 
object is alive) then a set of "del self.xxx" statements is required 
instead, so you've just replaced one problem with another ;)


I'd rather just explicitly say what I want to happen rather than have 
*everything* happen and then have to tidy that up instead ...


E.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Mike Miller


On 2017-04-25 15:05, Paul Moore wrote:

It seems to me that the number of people for whom both of the following hold:

1. Writing out the assignments "longhand" is an unacceptable burden.
2. Using a decorator (which can be written directly in your project,
doesn't even need to be an external dependency) is unacceptable.

is likely to be small enough that it's not a compelling argument for
adding new syntax. Add to that the fact that these people would be
arguing "I want the ability to avoid writing out the assignments, but
I don't want that capability enough to use a decorator" - which hardly
says that a syntax change is vital - and it's difficult to see this
proposal getting accepted.


While the word unacceptable is probably a bit too strong, this is a good 
insight.  We have a "middling" difficulty here.  Not the end of the world, but 
an annoyance, as the existence of the attrs library demonstrates.  Kivy's 
properties solve a similar problem (though a bit different scope).  I've 
overheard Java snobs sneer at Python's init so it is a well known issue.


If there is going to be a solution, I submit it needs to be much easier to use 
and to read.  Making it a little easier is not good enough, not enough reason to 
change.  (Believe you mentioned a 3 to 2 reduction elsewhere in the thread.)  Meh.


If I have install a module in pip and go back to the top of the file and write 
an import line and then come back and write out a decorator it's not going to be 
worth it.  Currently, I use editor snippets to ease authoring of init, but 
readability and DRY are still concerns afterward.


As the new syntax ideas piggyback on existing syntax, it doesn't feel like that 
its a complete impossibility to have this solved.  Could be another "fixed 
papercut" to drive Py3 adoption.  Taken individually not a big deal but they add up.

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread MRAB

On 2017-04-26 18:46, Mike Miller wrote:


On 2017-04-26 04:12, Brice PARENT wrote:

Why not simply do this :

class MyClass:
def _set_multiple(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)

def __init__(self, a, b, c):
self._set_multiple(a=a, b=b, c=c)


If the goal is to not have to type out argument names three times (in DRY
fashion), this doesn't quite fit the bill.


An alternative is to use a special comment, for example:

class MyClass:
def __init__(self, a, b, c):
#> a, b, c

And then use, say, a Python script to expand it to:

class MyClass:
def __init__(self, a, b, c):
#> a, b, c
self.a = a
self.b = b
self.c = c
#<

The Python script could be called from the editor.

If you want to add or remove an argument, edit the comment and then run 
the script again. (Hopefully it'll be smart enough to make the necessary 
changes).

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Juancarlo Añez
On Wed, Apr 26, 2017 at 11:17 AM, Erik  wrote:

> I had forgotten that decorators could take parameters. Something like that
> pretty much ticks the boxes for me.
>

There are decorators with "include"  and "included" in this SO Q:

http://stackoverflow.com/q/3652851/545637


> I'd _prefer_ something that sits inside the method body rather than just
> outside it, and I'd probably _prefer_ something that wasn't quite so
> heavyweight at runtime (which may be an irrational concern on my part ;)),
>

The same strategies applied by the decorators may be applied by a by a
function called from within __init__.


> but those aren't deal breakers, depending on the project - and the vast
> majority of what I do in Python is short-lived one-off projects and rapid
> prototyping for later implementation in another language, so I do seem to
> be fleshing out a set of classes from scratch and writing a bunch of
> __init__ methods far more of the time than people with long-lived projects
> would do. Perhaps that's why it irritates me more than it does some others
> ;)
>

For the cases I've found in which classes define several attributes that
are initialized in the constructor I think that a library like
https://github.com/python-attrs/attrs does what's needed. The downside is
that code-writing tools (like IDEs) don't understand what's going on under
the hood.

-- 
Juancarlo *Añez*
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Mike Miller


On 2017-04-26 04:12, Brice PARENT wrote:

Why not simply do this :

class MyClass:
def _set_multiple(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)

def __init__(self, a, b, c):
self._set_multiple(a=a, b=b, c=c)


If the goal is to not have to type out argument names three times (in DRY 
fashion), this doesn't quite fit the bill.


-Mike

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Mike Miller


On 2017-04-25 15:30, Erik wrote:


All of the decorators (or other language tricks that modify the object's dict)
suggested so far assume that ALL of the method's arguments are to be assigned. I
do not want that. I want to be able to say:

def __init__(self, foo, bar, baz, spam):
  self .= foo, bar, spam
  self.baz = baz * 100



I don't see ALL being set a big problem, and less work than typing several of 
them out again.


Just because all args get set at once, doesn't mean the init stops there and 
attributes can't be further modified or deleted.  In your example above, you 
modify baz afterward as an argument that might need to be changed, as they often do.


If this doesn't give enough control, the manual way is always available.
Setting them all makes simple things *very* simple, and the medium and 
complicated still possible.

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Paul Moore
On 26 April 2017 at 16:17, Erik  wrote:
> On 26/04/17 08:59, Paul Moore wrote:
>>
>> It should be possible to modify the decorator to take a list
>> of the variable names you want to assign, but I suspect you won't like
>> that
>
>
> Now you're second-guessing me.

Sorry :-)

>> class MyClass:
>> @auto_args('a', 'b')
>> def __init__(self, a, b, c=None):
>> pass
>
> I had forgotten that decorators could take parameters. Something like that
> pretty much ticks the boxes for me.

Cool. Glad you liked the idea.

Paul
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Erik

On 26/04/17 08:59, Paul Moore wrote:

It should be possible to modify the decorator to take a list
of the variable names you want to assign, but I suspect you won't like
that


Now you're second-guessing me.

> class MyClass:
> @auto_args('a', 'b')
> def __init__(self, a, b, c=None):
> pass

I had forgotten that decorators could take parameters. Something like 
that pretty much ticks the boxes for me.


I'd _prefer_ something that sits inside the method body rather than just 
outside it, and I'd probably _prefer_ something that wasn't quite so 
heavyweight at runtime (which may be an irrational concern on my part 
;)), but those aren't deal breakers, depending on the project - and the 
vast majority of what I do in Python is short-lived one-off projects and 
rapid prototyping for later implementation in another language, so I do 
seem to be fleshing out a set of classes from scratch and writing a 
bunch of __init__ methods far more of the time than people with 
long-lived projects would do. Perhaps that's why it irritates me more 
than it does some others ;)


E.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Erik

On 26/04/17 13:19, Joao S. O. Bueno wrote:

On 25 April 2017 at 19:30, Erik  wrote:

decorators don't cut it anyway (at least not those
proposed) because they blindly assign ALL of the arguments. I'm more than
happy to hear of something that solves both of those problems without
needing syntax changes though, as that means I can have it today ;)


Sorry -  a decorator won't "blindly assign all argments" - it will do
that just if it is written to do so.


Right, and the three or four variants suggested (and the 
vars(self).update() suggestion) all do exactly that. I was talking about 
the specific responses (though I can see my language is vague).


[FWIW I've been using Python the whole time that decorators have existed 
and I've yet to need to write one - I've _used_ some non-parameterized 
ones though - so I guess I'd forgotten that they can take parameters]


E.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Carlo Miron
On Wed, Apr 26, 2017 at 2:02 PM,   wrote:

>> On Wed, Apr 26, 2017 at 01:12:14PM +0200, Brice PARENT
>>  wrote:
>> > def _set_multiple(self, **kwargs):
>> > for key, value in kwargs.items():
>> > setattr(self, key, value)
>>
>> self.__dict__.update(kwargs)
>
> Touching __dict__ feels dirty to me.

vars(self).update(kwargs)?

㎝

-- 
|:**THE -WARE LICENSE** *(Revision ㊷)*:
|  wrote this mail. As long as you retain this
| notice you can do whatever you want with this stuff.
| If we meet some day, and you think this stuff is worth it,
| you can buy me a  in return. —㎝
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Joao S. O. Bueno
On 25 April 2017 at 19:30, Erik  wrote:
> And as I also said above, decorators don't cut it anyway (at least not those
> proposed) because they blindly assign ALL of the arguments. I'm more than
> happy to hear of something that solves both of those problems without
> needing syntax changes though, as that means I can have it today ;)

Sorry -  a decorator won't "blindly assign all argments" - it will do
that just if it is written to do so.

It is perfectly feasible to have a decorator to which you can simply
pass a list of not wanted auto-parameters, or that will just
auto-assign parameters that have been declared on the class body, or
even inspect the function signature and check for special annotations
- there are tens of ways we could spec a list of exceptions to such a
decorator, and still avouid typing three times each name.

That said, I am all in favor of the addition of such a decorator to the stdlib.

   js
  -><-
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Oleg Broytman
On Wed, Apr 26, 2017 at 01:12:14PM +0200, Brice PARENT  
wrote:
> def _set_multiple(self, **kwargs):
> for key, value in kwargs.items():
> setattr(self, key, value)

self.__dict__.update(kwargs)

Oleg.
-- 
 Oleg Broytmanhttp://phdru.name/p...@phdru.name
   Programmers don't die, they just GOSUB without RETURN.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-26 Thread Paul Moore
On 25 April 2017 at 23:30, Erik  wrote:
> As I said above, it's not about the effort writing it out. It's about the
> effort (and accuracy) of reading the code after it has been written.

Well, personally I find all of the syntax proposals relatively
unreadable. So that's definitely a matter of opinion. And the
"explicit is better than implicit" principle argues for the longhand
form.

As has been pointed out, the case for += is more about incremented
complex computed cases than simply avoiding repeating a variable name
(although some people find that simpler case helpful, too - I'm
personally ambivalent).

> And as I also said above, decorators don't cut it anyway (at least not those
> proposed) because they blindly assign ALL of the arguments. I'm more than
> happy to hear of something that solves both of those problems without
> needing syntax changes though, as that means I can have it today ;)

That's something that wasn't clear from your original post, but you're
correct. It should be possible to modify the decorator to take a list
of the variable names you want to assign, but I suspect you won't like
that - it does reduce the number of times you have to name the
variables from 3 to 2, the same as your proposal, though.

class MyClass:
@auto_args('a', 'b')
def __init__(self, a, b, c=None):
pass

Paul
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-25 Thread Juancarlo Añez
On Tue, Apr 25, 2017 at 6:09 PM, Paul Moore  wrote:

> (Arguing for auto_args to be in the stdlib may be a better option than
> arguing for new syntax, BTW...)
>

Having such a decorator in the stdlib would allow IDEs and syntax
highlighters to know what's going on.


-- 
Juancarlo *Añez*
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-25 Thread Nathaniel Smith
On Tue, Apr 25, 2017 at 3:30 PM, Erik  wrote:
> On 25/04/17 23:05, Paul Moore wrote:
>>
>> 1. Writing out the assignments "longhand" is an unacceptable burden.
>
>
> There are reasons why augmented assignment was implemented. One of them was
> to make the code easier to read:
>
>   foil = foil + 1
>   foil = foi1 + 1
>   foil += 1
>
> Should one be silly enough to have a "foil" and "foi1" variable in scope,
> only one of those is clearly incrementing a variable without requiring a
> slightly harder look ;)

But if this were the only argument for +=, then I'm not sure it would
have ever been added :-).

The really compelling cases for += are things like:

foo.some_attr[get_the_key(kwarg=something)] =
foo.some_attr[get_the_key(kwarg=something)] + 1

vs

foo.some_attr[get_the_key(kwarg=something)] += 1

where the latter is *much* more readable, and it only calls
get_the_key once, which (depending on what it does) may be both a
substantial efficiency win and also guarantees this is actually an
increment – we don't have to read get_the_key's source code first to
figure out if the two calls actually return the same value.

Another example:

arr = arr + 1
arr += 1

If 'arr' is a numpy array then these actually do very different
things: the first one allocates a new array and then rebinds the name
'arr' to the copy; the second modifies the array object in place. The
former is usually what you want, but without augmented assignment you
have to remember to do awkward things like 'arr[...] = arr + 1'. And
it gets worse: since 'arr[...] = arr + 1' has to make a copy, it's
about twice as slow as 'arr += 1'. The real equivalent of 'arr += 1'
is 'np.add(arr, 1, out=arr)', which is *really* bad.

Are there any similar arguments for .=?

-n

-- 
Nathaniel J. Smith -- https://vorpus.org
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-25 Thread Chris Angelico
On Wed, Apr 26, 2017 at 10:05 AM, Ryan Gonzalez  wrote:
> FWIW I always liked
> Dart's/Ruby's/Crystal's/(Coffee|Moon)Script's/WhateverElse's style:
>
>
> class Cls {
>   Cls(this.a);  // IT'S MAGIC
> }
>
>
> but the Python equivalent is admittedly weirder:
>
>
> def ___init__(self, self.attr):

In a sense, what you have is this (modulo keyword arguments):

def __init__(*args):
self, self.attr = args

which is perfectly legal, albeit weird. So it needn't actually be
magic per se, just a change in the definition of an argument name
(from NAME to whatever is legal as an assignment target).

I don't think it's particularly useful, though.

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-25 Thread Ryan Gonzalez
FWIW I always liked
Dart's/Ruby's/Crystal's/(Coffee|Moon)Script's/WhateverElse's style:


class Cls {
  Cls(this.a);  // IT'S MAGIC
}


but the Python equivalent is admittedly weirder:


def ___init__(self, self.attr):


partly because, it'd have to work on pretty much any other variable name,
yet there's no other real use case outside of methods.


--
Ryan (ライアン)
Yoko Shimomura > ryo (supercell/EGOIST) > Hiroyuki Sawano >> everyone else
http://refi64.com

On Apr 24, 2017 8:08 PM, "Erik"  wrote:

> Hi. I suspect that this may have been discussed to death at some point in
> the past, but I've done some searching and I didn't come up with much.
> Apologies if I'm rehashing an old argument ;)
>
> I often find myself writing __init__ methods of the form:
>
> def __init__(self, foo, bar, baz, spam, ham):
>   self.foo = foo
>   self.bar = bar
>   self.baz = baz
>   self.spam = spam
>   self.ham = ham
>
> This seems a little wordy and uses a lot of vertical space on the screen.
> Occasionally, I have considered something like:
>
> def __init__(self, foo, bar, baz, spam, ham):
>   self.foo, self.bar, self.baz, self.spam, self.ham = \
>  foo, bar, baz, spam, ham
>
> ... just to make it a bit more compact - though in practice, I'd probably
> not do that with a list quite that long ... two or three items at most:
>
> def __init__(self, foo, bar, baz):
>self.foo, self.bar, self.baz = foo, bar, baz
>
> When I do that I'm torn because I know it has a runtime impact to create
> and unpack the implicit tuples and I'm also introducing a style asymmetry
> in my code just because of the number of parameters a method happens to
> have.
>
> So why not have an augmented assignment operator for object attributes? It
> addresses one of the same broad issues that the other augmented assignment
> operators were introduced for (that of repeatedly spelling names).
>
> The suggestion therefore is:
>
> def __init__(self, foo, bar, baz, spam, ham):
>   self .= foo, bar, baz, spam, ham
>
> This is purely syntactic sugar for the original example:
>
> def __init__(self, foo, bar, baz, spam, ham):
>   self.foo = foo
>   self.bar = bar
>   self.baz = baz
>   self.spam = spam
>   self.ham = ham
>
> ... so if any of the attributes have setters, then they are called as
> usual. It's purely a syntactic shorthand. Any token which is not suitable
> on the RHS of the dot in a standard "obj.attr =" assignment is a syntax
> error (no "self .= 1").
>
> The comma-separators in the example are not creating a tuple object, they
> would work at the same level in the parser as the import statement's
> comma-separated lists - in the same way that "from pkg import a, b, c" is
> the same as saying:
>
> import pkg
> a = pkg.a
> b = pkg.b
> c = pkg.c
>
> ... "self .= a, b, c" is the same as writing:
>
> self.a = a
> self.b = b
> self.c = c
>
> E.
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-25 Thread Matt Gilson
On Tue, Apr 25, 2017 at 4:31 PM, Erik  wrote:

> On 25/04/17 22:15, Brice PARENT wrote:
>
>> it may be easier to get something like this
>> (I think, as there is no new operator involved) :
>>
>
> No new operator, but still a syntax change, so that doesn't help from that
> POV.
>
>
>> def __init__(self, *args, **kwargs):
>>   self.* = *args
>>   self.** = **kwargs
>>
>
> What is "self.* = *args" supposed to do? For each positional argument,
> what name in the object is it bound to?
>
> E.


For what it's worth, that's what I don't really like about the initially
proposed syntax too ...

self .= foo, bar, baz

works OK, but:

tup = foo, bar, baz
self .= tup

doesn't work.  Admittedly, that could be part of the definition of this
feature, but it feels really unexpected to all of a sudden give my tuple a
temporary name and have the code behave in a dramatically different fashion.


>
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>



-- 

Matt Gilson | Pattern

Software Engineer
getpattern.com

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-25 Thread Erik

On 25/04/17 22:15, Brice PARENT wrote:

it may be easier to get something like this
(I think, as there is no new operator involved) :


No new operator, but still a syntax change, so that doesn't help from 
that POV.




def __init__(self, *args, **kwargs):
  self.* = *args
  self.** = **kwargs


What is "self.* = *args" supposed to do? For each positional argument, 
what name in the object is it bound to?


E.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-25 Thread Erik

On 25/04/17 02:15, Chris Angelico wrote:

Bikeshedding: Your example looks a lot more like tuple assignment than
multiple assignment.


Well, originally, I thought it was just the spelling-the-same-name-twice 
thing that irritated me and I was just going to suggest a single 
assignment version like:


  self .= foo
  self .= bar

Then I thought that this is similar to importing (referencing an object 
from one namespace in another under the same name). In that scenario, 
instead of:


  from other import foo
  from other import bar

we have:

  from other import foo, bar

That's where the comma-separated idea came from, and I understand it 
looks like a tuple (which is why I explicitly mentioned that) but it 
does in the import syntax too ;)


The single argument version (though it doesn't help with vertical space) 
still reads better to me for the same reason that augmented assignment 
is clearer - there is no need to mentally parse that the same name is 
being used on both sides of the assignment because it's only spelled once.



self .= foo .= bar .= baz .= spam .= ham


Thanks for being the only person so far to understand that I don't 
necessarily want to bind ALL of the __init__ parameters to the object, 
just the ones I explicitly reference, but I'm not convinced by this 
suggestion. In chained assignment the thing on the RHS is bound to each 
name to the left of it and that is really not happening here.



The trouble is that this syntax is really only going to be used inside
__init__.


Even if that was true, who ever writes one of those? :D

E.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-25 Thread Mike Miller



On 2017-04-25 14:15, Brice PARENT wrote:

But, any of these proposals, mine and yours, if you really need this to shorten
the code writing time or vertical space only, is not a better idea than to
propose a macro to your IDE editor, or a pull request if it's open source. Such
a macro would generate automatically those long-to-write lines, and maybe
implement some code folding if vertical space is an issue.


I'm personally not bothered by vertical space, but rather typing the same thing 
three times with self's and ='s.  That's more boilerplate than Java.  ;)

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-25 Thread Mike Miller
Agreed with Steven, although I do find myself a little more annoyed and bothered 
by a typical init than him I guess.


Even so I didn't think the current proposals went far enough.  To tilt the 
balance farther, to make it easier, let's go all the way!  Instead of continuing 
duplication:



>>> def __init__(self, foo, bar, baz, spam, ham):
  self .= foo, bar, baz, spam, ham


or


# object member assignment
self .= foo .= bar .= baz .= spam .= ham


How about?

def __init__(self, foo, bar, baz, spam, ham):
  self .= *

The asterisk here used to be reminiscent of argument unpacking (minus self). 
That would imply a double asterisk for keyword assignment which could be used as 
well.


Also, I did find the decorator proposal intriguing, though have to say I 
probably wouldn't bother to use it unless it were a builtin or I had a dozen 
parameters to deal with.


-Mike
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-25 Thread Tin Tvrtković
You might want to check out attrs (http://attrs.readthedocs.io/en/stable/).
It can generate the __init__ for you, and much much more.


Date: Tue, 25 Apr 2017 14:33:49 +0200
> From: George Fischhof <geo...@fischhof.hu>
> To: Paul Moore <p.f.mo...@gmail.com>
> Cc: Python-Ideas <python-ideas@python.org>, "Steven D'Aprano"
>         <st...@pearwood.info>
> Subject: Re: [Python-ideas] Augmented assignment syntax for objects.
> Message-ID:
> <
> cafwcp0gjg1bxeq2pmv637bxg6+vcxivu1qnekdetuhjmot_...@mail.gmail.com>
> Content-Type: text/plain; charset="utf-8"
>
> 2017. ?pr. 25. de. 10:04 ezt ?rta ("Paul Moore" <p.f.mo...@gmail.com>):
>
> On 25 April 2017 at 03:53, Steven D'Aprano <st...@pearwood.info> wrote:
> > On Tue, Apr 25, 2017 at 02:08:05AM +0100, Erik wrote:
> >
> >> I often find myself writing __init__ methods of the form:
> >>
> >> def __init__(self, foo, bar, baz, spam, ham):
> >>   self.foo = foo
> >>   self.bar = bar
> >>   self.baz = baz
> >>   self.spam = spam
> >>   self.ham = ham
> >>
> >> This seems a little wordy and uses a lot of vertical space on the
> >> screen.
> >
> > It does, and while both are annoying, in the grand scheme of things
> > they're a very minor annoyance. After all, this is typically only an
> > issue once per class, and not even every class, and vertical space is
> > quite cheap. In general, the barrier for accepting new syntax is quite
> > high, and "minor annoyance" generally doesn't reach it.
>
> I suspect that with a suitably creative use of inspect.signature() you
> could write a decorator for this:
>
> @auto_attrs
> def __init__(self, a, b, c):
> # Remaining init code, called with self.a, self.b and self.c set
>
> I don't have time to experiment right now, but will try to find time
> later. If nothing else, such a decorator would be a good prototype for
> the proposed functionality, and may well be sufficient for the likely
> use cases without needing a syntax change.
>
> Paul
>
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-25 Thread George Fischhof
2017. ápr. 25. de. 10:04 ezt írta ("Paul Moore" ):

On 25 April 2017 at 03:53, Steven D'Aprano  wrote:
> On Tue, Apr 25, 2017 at 02:08:05AM +0100, Erik wrote:
>
>> I often find myself writing __init__ methods of the form:
>>
>> def __init__(self, foo, bar, baz, spam, ham):
>>   self.foo = foo
>>   self.bar = bar
>>   self.baz = baz
>>   self.spam = spam
>>   self.ham = ham
>>
>> This seems a little wordy and uses a lot of vertical space on the
>> screen.
>
> It does, and while both are annoying, in the grand scheme of things
> they're a very minor annoyance. After all, this is typically only an
> issue once per class, and not even every class, and vertical space is
> quite cheap. In general, the barrier for accepting new syntax is quite
> high, and "minor annoyance" generally doesn't reach it.

I suspect that with a suitably creative use of inspect.signature() you
could write a decorator for this:

@auto_attrs
def __init__(self, a, b, c):
# Remaining init code, called with self.a, self.b and self.c set

I don't have time to experiment right now, but will try to find time
later. If nothing else, such a decorator would be a good prototype for
the proposed functionality, and may well be sufficient for the likely
use cases without needing a syntax change.

Paul
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/



Hi, such a decorator would be very grateful ;-) in the standard as for
example I use class parameters this way too in more than 90% of the cases.

BR
George
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-25 Thread Daniel Moisset
I actually saw a decorator like that last week,
https://twitter.com/judy2k/status/854330478068977664

On 25 April 2017 at 08:56, Paul Moore  wrote:

> On 25 April 2017 at 03:53, Steven D'Aprano  wrote:
> > On Tue, Apr 25, 2017 at 02:08:05AM +0100, Erik wrote:
> >
> >> I often find myself writing __init__ methods of the form:
> >>
> >> def __init__(self, foo, bar, baz, spam, ham):
> >>   self.foo = foo
> >>   self.bar = bar
> >>   self.baz = baz
> >>   self.spam = spam
> >>   self.ham = ham
> >>
> >> This seems a little wordy and uses a lot of vertical space on the
> >> screen.
> >
> > It does, and while both are annoying, in the grand scheme of things
> > they're a very minor annoyance. After all, this is typically only an
> > issue once per class, and not even every class, and vertical space is
> > quite cheap. In general, the barrier for accepting new syntax is quite
> > high, and "minor annoyance" generally doesn't reach it.
>
> I suspect that with a suitably creative use of inspect.signature() you
> could write a decorator for this:
>
> @auto_attrs
> def __init__(self, a, b, c):
> # Remaining init code, called with self.a, self.b and self.c set
>
> I don't have time to experiment right now, but will try to find time
> later. If nothing else, such a decorator would be a good prototype for
> the proposed functionality, and may well be sufficient for the likely
> use cases without needing a syntax change.
>
> Paul
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>



-- 
Daniel F. Moisset - UK Country Manager
www.machinalis.com
Skype: @dmoisset
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-25 Thread Paul Moore
On 25 April 2017 at 03:53, Steven D'Aprano  wrote:
> On Tue, Apr 25, 2017 at 02:08:05AM +0100, Erik wrote:
>
>> I often find myself writing __init__ methods of the form:
>>
>> def __init__(self, foo, bar, baz, spam, ham):
>>   self.foo = foo
>>   self.bar = bar
>>   self.baz = baz
>>   self.spam = spam
>>   self.ham = ham
>>
>> This seems a little wordy and uses a lot of vertical space on the
>> screen.
>
> It does, and while both are annoying, in the grand scheme of things
> they're a very minor annoyance. After all, this is typically only an
> issue once per class, and not even every class, and vertical space is
> quite cheap. In general, the barrier for accepting new syntax is quite
> high, and "minor annoyance" generally doesn't reach it.

I suspect that with a suitably creative use of inspect.signature() you
could write a decorator for this:

@auto_attrs
def __init__(self, a, b, c):
# Remaining init code, called with self.a, self.b and self.c set

I don't have time to experiment right now, but will try to find time
later. If nothing else, such a decorator would be a good prototype for
the proposed functionality, and may well be sufficient for the likely
use cases without needing a syntax change.

Paul
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-24 Thread Nathaniel Smith
On Mon, Apr 24, 2017 at 6:08 PM, Erik  wrote:
> Hi. I suspect that this may have been discussed to death at some point in
> the past, but I've done some searching and I didn't come up with much.
> Apologies if I'm rehashing an old argument ;)
>
> I often find myself writing __init__ methods of the form:
>
> def __init__(self, foo, bar, baz, spam, ham):
>   self.foo = foo
>   self.bar = bar
>   self.baz = baz
>   self.spam = spam
>   self.ham = ham

This isn't a direct response, but you might be interested in the attrs library:
https://attrs.readthedocs.io/en/stable/examples.html

-n

-- 
Nathaniel J. Smith -- https://vorpus.org
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-24 Thread Steven D'Aprano
On Tue, Apr 25, 2017 at 02:08:05AM +0100, Erik wrote:

> I often find myself writing __init__ methods of the form:
> 
> def __init__(self, foo, bar, baz, spam, ham):
>   self.foo = foo
>   self.bar = bar
>   self.baz = baz
>   self.spam = spam
>   self.ham = ham
> 
> This seems a little wordy and uses a lot of vertical space on the 
> screen. 

It does, and while both are annoying, in the grand scheme of things 
they're a very minor annoyance. After all, this is typically only an 
issue once per class, and not even every class, and vertical space is 
quite cheap. In general, the barrier for accepting new syntax is quite 
high, and "minor annoyance" generally doesn't reach it.

I'm completely with you about the annoyance factor here. It is 
especially annoying during the early stages of development when the 
__init__ method is evolving rapidly (parameters are being renamed, added 
or removed). One work-around is this pattern:

def __init__(self, spam, ham, eggs, cheese, aardvark):
vars(self).update(locals())
del self.self
...


which is cute but I've never quite been brave enough to use it in 
production. But I don't think the annoyance factor is high enough, or 
common enough, to justify syntactic sugar to "fix" it.



> Occasionally, I have considered something like:
> 
> def __init__(self, foo, bar, baz, spam, ham):
>   self.foo, self.bar, self.baz, self.spam, self.ham = \
>  foo, bar, baz, spam, ham
> 
> ... just to make it a bit more compact
[...]
> When I do that I'm torn because I know it has a runtime impact to create 
> and unpack the implicit tuples and I'm also introducing a style 
> asymmetry in my code just because of the number of parameters a method 
> happens to have.

I'm not too worried about the performance impact unless I've 
profiled my code and it is actually significant.

As far as the style asymmetry, if we use your proposed syntax, that's 
introducing style asymmetry too.



> So why not have an augmented assignment operator for object attributes? 

Wrong question. Don't ask "why not add this feature?". The question to 
ask is "why add this feature?" Every new feature has cost, whether it is 
run-time cost, development cost, feature bloat, learning curve cost, 
etc, so the feature must be justified as adding sufficiently more 
value than it costs.

Here are a few reasons why this feature fails to meet the barrier for 
new syntax.

- This feature doesn't add any new capability to the language. There's 
nothing that this feature allows you to do which you couldn't do before.

- It has quite narrow applicability. It's really only useful inside a 
small proportion of __init__ methods.

- In my experience, it is very rare to have a whole set of unadorned 
assignments in the way you show it. MUCH more common is to have some 
sort of pre-processing of the argument before assignment, or for the 
assignment target to be different from the parameter name:


def __init__(self, spam, eggs, cheese, aardvark, ...):
# type checks
if not isinstance(spam, Foo):
raise TypeError
self._spam = spam  # not all parameters are public attributes
# value checks
if eggs < 0:
raise ValueError
self.eggs = eggs
# replacement of None
if cheese is None:
cheese = make_cheese()
self.cheese = cheese
# other pre-processing
self.mammals = [aardvark, get_weasel()]


which reduces the applicability of this syntax even further.

- Having big parameter lists is something of a mild code smell. As the 
parameter list gets bigger, the smell gets worse. Having so many 
parameters that this feature becomes attractive should be painful, 
because its a warning that maybe your class has too many parameters.



> It addresses one of the same broad issues that the other augmented 
> assignment operators were introduced for (that of repeatedly spelling 
> names).
> 
> The suggestion therefore is:
> 
> def __init__(self, foo, bar, baz, spam, ham):
>   self .= foo, bar, baz, spam, ham

But there's a major difference between this and the other augmented 
assignment operators, so major that the analogy between them doesn't 
hold up.

In augmented assignment, the target can be any valid target, and the RHS 
can be any expression

mylist[0].attr['key'] += (some_value() or another) + 99

Your suggestion is very different: there are *many* targets, and the RHS 
must be a comma-separated list of identifiers. They're quite different 
kinds of assignment. And unlike augmented assignment, which calls one of 
the __iop__ methods, this would have to be handled purely as syntax.

> This is purely syntactic sugar for the original example:
> 
> def __init__(self, foo, bar, baz, spam, ham):
>   self.foo = foo
>   self.bar = bar
>   self.baz = baz
>   self.spam = spam
>   self.ham = ham
> 
> ... so if any of the attributes have setters, then they are called as 
> usual. It's purely a 

Re: [Python-ideas] Augmented assignment syntax for objects.

2017-04-24 Thread Chris Angelico
On Tue, Apr 25, 2017 at 11:08 AM, Erik  wrote:
> The suggestion therefore is:
>
> def __init__(self, foo, bar, baz, spam, ham):
>   self .= foo, bar, baz, spam, ham
>
> This is purely syntactic sugar for the original example:
>
> def __init__(self, foo, bar, baz, spam, ham):
>   self.foo = foo
>   self.bar = bar
>   self.baz = baz
>   self.spam = spam
>   self.ham = ham
>
> ... so if any of the attributes have setters, then they are called as usual.
> It's purely a syntactic shorthand. Any token which is not suitable on the
> RHS of the dot in a standard "obj.attr =" assignment is a syntax error (no
> "self .= 1").

Bikeshedding: Your example looks a lot more like tuple assignment than
multiple assignment. I'd rather it link more with the way that
multiple assignment works:

# simple multiple assignment
a = b = c = d = e = 0
# object member assignment
self .= foo .= bar .= baz .= spam .= ham

The trouble is that this syntax is really only going to be used inside
__init__. It's hard to justify new syntax for one purpose like this.
So I'm swaying between -0 and +0.5 on this.

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/