Re: Search a sequence for its minimum and stop as soon as the lowest possible value is found

2017-01-08 Thread Paul Rubin
Jussi Piitulainen  writes:
> That would return 0 even when there is no 0 in xs at all.

Doesn't look that way to me:

>>> minabs([5,3,1,2,4])
1
-- 
https://mail.python.org/mailman/listinfo/python-list


RE: Using namedtuples field names for column indices in a list of lists

2017-01-08 Thread Deborah Swanson
Steven D'Aprano wrote, on January 07, 2017 10:43 PM
> 
> On Sunday 08 January 2017 16:39, Deborah Swanson wrote:
> 
> > What I've done so far:
> > 
> > with open('E:\\Coding projects\\Pycharm\\Moving\\Moving 
> 2017 in.csv',
> > 'r') as infile:
> > ls = list(csv.reader(infile))
> > lst = namedtuple('lst', ls[0])
> > 
> > where 'ls[0]' is the header row of the csv, and it works perfectly 
> > well. 'lst' is a namedtuple instance with each of the 
> column titles as 
> > field names.
> 
> Are you sure? namedtuple() returns a class, not a list:

Yes. 'ls' is defined as 'list(csv.reader(infile))', so ls[0] is the
first row from the csv, the header row. 'lst' is the namedtuple.

Perhaps what's puzzling you is that the way I've written it, the list of
data and the namedtuple are disjoint, and that's the problem.

> py> from collections import namedtuple
> py> names = ['A', 'B', 'C']
> py> namedtuple('lst', names)
> 
> 
> The way namedtuple() is intended to be used is like this:
> 
> 
> py> from collections import namedtuple
> py> names = ['A', 'B', 'C']
> py> Record = namedtuple('Record', names)
> py> instance = Record(10, 20, 30)
> py> print(instance)
> Record(A=10, B=20, C=30)
> 
> 
> There is no need to call fget directly to access the 
> individual fields:
> 
> py> instance.A
> 10
> py> instance.B
> 20
> py> instance[1]  # indexing works too
> 20
> 
> 
> which is *much* simpler than:
> 
> py> Record.A.fget(instance)
> 10
 
I don't disagree with anything you've said and shown here. But I want to
use the 'instance.A' as a subscript for the list 'ls', and the only way
to do that is with .fget(). Believe me, I tried every possible way to
use instance.A or instance[1] and no way could I get ls[instance.A]. 

The problem I'm having here is one of linkage between the named tuple
for the column titles and the list that holds the data in the columns.

> I think you should be doing something like this:
> 
> pathname = 'E:\\Coding projects\\Pycharm\\Moving\\Moving 2017 
> in.csv' with open(pathname, 'r') as infile:
> rows = list(csv.reader(infile))
> Record = namedtuple("Record", rows[0])
> for row in rows[1:]:  # skip the first row, the header
> row = Record(row)
> # process this row...
> if row.location == 0:
> ...

Now here you have something I didn't think of: 'row = Record(row)' in a
loop through the rows. 

> [...]
> > But I haven't found a way to assign new values to a list element. 
> > using namedtuple.fieldname. I think a basic problem is that 
> > namedtuples have the properties of tuples, and you can't assign to
an 
> > existing tuple because they're immutable.
> 
> Indeed. Being tuples, you have to create a new one. You can 
> do it with slicing, 
> like ordinary tuples, but that's rather clunky:
> 
> py> print(instance)
> Record(A=10, B=20, C=30)
> py> Record(999, *instance[1:])
> Record(A=999, B=20, C=30)

Very clunky. I don't like modifying standard tuples with slicing, and
this is even worse.

> The recommended way is with the _replace method:
> 
> py> instance._replace(A=999)
> Record(A=999, B=20, C=30)
> py> instance._replace(A=999, C=888)
> Record(A=999, B=20, C=888)
> 
> 
> Note that despite the leading underscore, _replace is *not* a 
> private method of 
> the class. It is intentionally documented as public. The 
> leading underscore is 
> so that it won't clash with any field names.
> 
> 
> 
> 
> -- 
> Steven
> "Ever since I learned about confirmation bias, I've been seeing 
> it everywhere." - Jon Ronson

I will have to work with this. It's entirely possible it will do what I
want it to do. The key problem I was having was getting a linkage
between the namedtuple and the list of data from the csv.

I want to implement a suggestion I got to use a namedtuple made from the
header row as subscripts for elements in the list of data, and the
example given in the docs: 

EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title,
department, paygrade')

import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv",
"rb"))):
print(emp.name, emp.title)

assumes the field names will be hardcoded. Reading the csv into a list
and then trying to use the namedtuple made from the header row as
subscripts is how I ended up resorting to 'Record.A.fget(instance)' to
read values, and wasn't able to assign them. 

But assigning the rows of data into namedtuple instances with: 

Record = namedtuple("Record", rows[0])
for row in rows[1:]: 
row = Record(row)

does look like the linkage I need and wasn't finding the way I was doing
it. If 'Record(row)' is the list data and the columns are the same as
defined in 'namedtuple("Record", rows[0])', it really should work. And I
didn't get it that _replace could be used to assign new values to
namedtuples (duh. Pretty clear now that I reread it, and all the row
data is in namedtuple instances.) 

The big question is whether the namedtuple instances can be used as
something recognizable as 

Re: Search a sequence for its minimum and stop as soon as the lowest possible value is found

2017-01-08 Thread Paul Rubin
Paul Rubin  writes:
> seems to work, but is ugly.  Maybe there's something better.

def minabs2(xs):
def z():
for x in xs:
yield abs(x), x
if x==0: break
return min(z())[1]

is the same thing but a little bit nicer.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Search a sequence for its minimum and stop as soon as the lowest possible value is found

2017-01-08 Thread Paul Rubin
Paul Rubin  writes:
> Doesn't look that way to me:
> >>> minabs([5,3,1,2,4])
> 1

There's a different problem though:

>>> minabs([1,2,3,0])
1

I think Python's version of iterators is actually buggy and at least the
first element of the rest of the sequence should be preserved.  There
are ways to fake it but they're too messy for something like this.  It
should be the default and might have been a good change for Python 3.

def minabs2(xs):
def z():
for x in xs:
yield x
if x==0: break
return min((abs(x),x) for x in z())[1]


seems to work, but is ugly.  Maybe there's something better.
-- 
https://mail.python.org/mailman/listinfo/python-list


RE: Using namedtuples field names for column indices in a list of lists

2017-01-08 Thread Peter Otten
Deborah Swanson wrote:

> to do that is with .fget(). Believe me, I tried every possible way to
> use instance.A or instance[1] and no way could I get ls[instance.A].

Sorry, no.

To get a list of namedtuple instances use:

rows = csv.reader(infile)
Record = namedtuple("Record", next(rows))
records = [Record._make(row) for row in rows]

If you want a column from a list of records you need to extract it manually:

columnA = [record.A for record in records]


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Search a sequence for its minimum and stop as soon as the lowest possible value is found

2017-01-08 Thread Peter Otten
Paul Rubin wrote:

> Paul Rubin  writes:
>> seems to work, but is ugly.  Maybe there's something better.
> 
> def minabs2(xs):
> def z():
> for x in xs:
> yield abs(x), x
> if x==0: break
> return min(z())[1]
> 
> is the same thing but a little bit nicer.

Yes, that's another variant of the decorate/undecorate approach combined 
with Wolfgang's local take_until(). The generalized form that cannot rely on 
the sequence items being orderable would be

firstitem = operator.itemgetter(0)


def stopmin_paul(items, *, key, stop):
def take_until():
for item in items:
k = key(item)
yield k, item
if k <= stop:
break
return min(take_until(), key=firstitem)[1]


-- 
https://mail.python.org/mailman/listinfo/python-list


RE: Using namedtuples field names for column indices in a list of lists

2017-01-08 Thread Deborah Swanson
Peter Otten wrote, on January 08, 2017 3:01 AM
> 
> Deborah Swanson wrote:
> 
> > to do that is with .fget(). Believe me, I tried every > possible way
to 
> > use instance.A or instance[1] and no way could I get ls[instance.A].
> 
> Sorry, no.

I quite agree, I was describing the dead end I was in from peeling the
list of data and the namedtuple from the header row off the csv
separately. That was quite obviously the wrong path to take, but I
didn't know what a good way would be.

> To get a list of namedtuple instances use:
> 
> rows = csv.reader(infile)
> Record = namedtuple("Record", next(rows))
> records = [Record._make(row) for row in rows]

This is slightly different from Steven's suggestion, and it makes a
block of records that I think would be iterable. At any rate all the
data from the csv would belong to a single data structure, and that
seems inherently a good thing.

a = records[i].A , for example

And I think that this would produce recognizable field names in my code
(which was the original goal) if the following works:

records[0] is the header row == ('Description', 'Location', etc.)

If I can use records[i].Location for the Location column data in row
'i', then I've got my recognizable-field-name variables.  

> If you want a column from a list of records you need to 
> extract it manually:
> 
> columnA = [record.A for record in records]

This is very neat. Something like a list comprehension for named tuples?

Thanks Peter, I'll try it all tomorrow and see how it goes.

PS. I haven't forgotten your defaultdict suggestion, I'm just taking the
suggestions I got in the "Cleaning up Conditionals" thread one at a
time, and I will get to defaultdict. Then I'll look at all of them and
see what final version of the code will work best with all the factors
to consider. 

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Search a sequence for its minimum and stop as soon as the lowest possible value is found

2017-01-08 Thread Jussi Piitulainen
Paul Rubin writes:

> Jussi Piitulainen writes:
>> That would return 0 even when there is no 0 in xs at all.
>
> Doesn't look that way to me:
>
> >>> minabs([5,3,1,2,4])
> 1

Sorry about that. I honestly meant to say it would return 1 even when
there was a single 0 at the very end. Somehow I got seriously confused.

You noticed the actual problem yourself.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Search a sequence for its minimum and stop as soon as the lowest possible value is found

2017-01-08 Thread Jussi Piitulainen
Paul Rubin writes:

> I think Python's version of iterators is actually buggy and at least
> the first element of the rest of the sequence should be preserved.
> There are ways to fake it but they're too messy for something like
> this.  It should be the default and might have been a good change for
> Python 3.

It could still be added as an option, to both takewhile and iter(_, _).
-- 
https://mail.python.org/mailman/listinfo/python-list


RE: Using namedtuples field names for column indices in a list of lists

2017-01-08 Thread Peter Otten
Deborah Swanson wrote:

> Peter Otten wrote, on January 08, 2017 3:01 AM
>> 
>> Deborah Swanson wrote:
>> 
>> > to do that is with .fget(). Believe me, I tried every > possible way
> to
>> > use instance.A or instance[1] and no way could I get ls[instance.A].
>> 
>> Sorry, no.
> 
> I quite agree, I was describing the dead end I was in from peeling the
> list of data and the namedtuple from the header row off the csv
> separately. That was quite obviously the wrong path to take, but I
> didn't know what a good way would be.
> 
>> To get a list of namedtuple instances use:
>> 
>> rows = csv.reader(infile)
>> Record = namedtuple("Record", next(rows))
>> records = [Record._make(row) for row in rows]
> 
> This is slightly different from Steven's suggestion, and it makes a
> block of records that I think would be iterable. At any rate all the
> data from the csv would belong to a single data structure, and that
> seems inherently a good thing.
> 
> a = records[i].A , for example
> 
> And I think that this would produce recognizable field names in my code
> (which was the original goal) if the following works:
> 
> records[0] is the header row == ('Description', 'Location', etc.)

Personally I would recommend against mixing data (an actual location) and 
metadata (the column name,"Location"), but if you wish my code can be 
adapted as follows:

infile = open("dictreader_demo.csv")
rows = csv.reader(infile)
fieldnames = next(rows)
Record = namedtuple("Record", fieldnames)
records = [Record._make(fieldnames)]
records.extend(Record._make(row) for row in rows)

If you want a lot of flexibility without doing the legwork yourself you 
might also have a look at pandas. Example session:

$ cat places.csv
Location,Description,Size
here,something,17
there,something else,10
$ python3
Python 3.4.3 (default, Nov 17 2016, 01:08:31) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pandas
>>> places = pandas.read_csv("places.csv")
>>> places
  Location Description  Size
0 here   something17
1there  something else10

[2 rows x 3 columns]
>>> places.Location
0 here
1there
Name: Location, dtype: object
>>> places.sort(columns="Size")
  Location Description  Size
1there  something else10
0 here   something17

[2 rows x 3 columns]
>>> places.Size.mean()
13.5

Be aware that there is a learning curve...
 
> If I can use records[i].Location for the Location column data in row
> 'i', then I've got my recognizable-field-name variables.
> 
>> If you want a column from a list of records you need to
>> extract it manually:
>> 
>> columnA = [record.A for record in records]
> 
> This is very neat. Something like a list comprehension for named tuples?
> 
> Thanks Peter, I'll try it all tomorrow and see how it goes.
> 
> PS. I haven't forgotten your defaultdict suggestion, I'm just taking the
> suggestions I got in the "Cleaning up Conditionals" thread one at a
> time, and I will get to defaultdict. Then I'll look at all of them and
> see what final version of the code will work best with all the factors
> to consider.


-- 
https://mail.python.org/mailman/listinfo/python-list


RE: Using namedtuples field names for column indices in a list of lists

2017-01-08 Thread Deborah Swanson
Peter Otten wrote, on January 08, 2017 5:21 AM
> 
> Deborah Swanson wrote:
> 
> > Peter Otten wrote, on January 08, 2017 3:01 AM
> >> 
> >> Deborah Swanson wrote:
> >> 
> >> > to do that is with .fget(). Believe me, I tried every > possible 
> >> > way
> > to
> >> > use instance.A or instance[1] and no way could I get 
> >> > ls[instance.A].
> >> 
> >> Sorry, no.
> > 
> > I quite agree, I was describing the dead end I was in from 
> peeling the 
> > list of data and the namedtuple from the header row off the csv 
> > separately. That was quite obviously the wrong path to take, but I 
> > didn't know what a good way would be.
> > 
> >> To get a list of namedtuple instances use:
> >> 
> >> rows = csv.reader(infile)
> >> Record = namedtuple("Record", next(rows))
> >> records = [Record._make(row) for row in rows]
> > 
> > This is slightly different from Steven's suggestion, and it makes a 
> > block of records that I think would be iterable. At any 
> rate all the 
> > data from the csv would belong to a single data structure, and that 
> > seems inherently a good thing.
> > 
> > a = records[i].A , for example
> > 
> > And I think that this would produce recognizable field names in my 
> > code (which was the original goal) if the following works:
> > 
> > records[0] is the header row == ('Description', 'Location', etc.)
> 
> Personally I would recommend against mixing data (an actual 
> location) and 
> metadata (the column name,"Location"), but if you wish my code can be 
> adapted as follows:
> 
> infile = open("dictreader_demo.csv")
> rows = csv.reader(infile)
> fieldnames = next(rows)
> Record = namedtuple("Record", fieldnames)
> records = [Record._make(fieldnames)]
> records.extend(Record._make(row) for row in rows)

Peter, this looks really good, and yes, I didn't feel so good about 
records[i].Location either, but it was the only way I could see to get
the recognizable variable names I want. By extending records from a
namedtuple of field names, I think it can be done cleanly. I'll try it
and see.

> If you want a lot of flexibility without doing the legwork 
> yourself you 
> might also have a look at pandas. Example session:
> 
> $ cat places.csv
> Location,Description,Size
> here,something,17
> there,something else,10
> $ python3
> Python 3.4.3 (default, Nov 17 2016, 01:08:31) 
> [GCC 4.8.4] on linux
> Type "help", "copyright", "credits" or "license" for more information.
> >>> import pandas
> >>> places = pandas.read_csv("places.csv")
> >>> places
>   Location Description  Size
> 0 here   something17
> 1there  something else10
> 
> [2 rows x 3 columns]
> >>> places.Location
> 0 here
> 1there
> Name: Location, dtype: object
> >>> places.sort(columns="Size")
>   Location Description  Size
> 1there  something else10
> 0 here   something17
> 
> [2 rows x 3 columns]
> >>> places.Size.mean()
> 13.5
> 
> Be aware that there is a learning curve...

Yes, and I'm sure the learning curve is steep. I watched a webinar on
pandas about a year ago, not to actually learn it, but just to take in
the big picture and see something people were really accomplishing with
python.  I won't take this on any time right away, but I'll definitely
keep it and work with it sometime. Maybe as just an intro to pandas,
using my data from the real estate project.


> > If I can use records[i].Location for the Location column 
> data in row 
> > 'i', then I've got my recognizable-field-name variables.
> > 
> >> If you want a column from a list of records you need to extract it 
> >> manually:
> >> 
> >> columnA = [record.A for record in records]
> > 
> > This is very neat. Something like a list comprehension for named 
> > tuples?
> > 
> > Thanks Peter, I'll try it all tomorrow and see how it goes.
> > 
> > PS. I haven't forgotten your defaultdict suggestion, I'm 
> just taking 
> > the suggestions I got in the "Cleaning up Conditionals" 
> thread one at 
> > a time, and I will get to defaultdict. Then I'll look at 
> all of them 
> > and see what final version of the code will work best with all the 
> > factors to consider.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Using namedtuples field names for column indices in a list of lists

2017-01-08 Thread Paul Rudin
"Deborah Swanson"  writes:

> Peter Otten wrote, on January 08, 2017 3:01 AM
>> 
>> columnA = [record.A for record in records]
>
> This is very neat. Something like a list comprehension for named tuples?

Not something like - this *is* a list comprehension - it creates a list
of named tuples.

The thing you iterate over within the comprehension can be any
iterator. (Of course you're going to run into problems if you try to
construct a list from an infinite iterator.)
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Search a sequence for its minimum and stop as soon as the lowest possible value is found

2017-01-08 Thread Paul Rubin
Peter Otten <__pete...@web.de> writes:
> return min(take_until(), key=firstitem)[1]

Actually, key=abs should work.  I realized that after posting.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Search a sequence for its minimum and stop as soon as the lowest possible value is found

2017-01-08 Thread Paul Rubin
Jussi Piitulainen  writes:
> It could still be added as an option, to both takewhile and iter(_, _).

That's too messy, it really should be pervasive in iterators.
-- 
https://mail.python.org/mailman/listinfo/python-list


RE: Using namedtuples field names for column indices in a list of lists

2017-01-08 Thread Deborah Swanson
Paul Rudin wrote, on January 08, 2017 6:49 AM
> 
> "Deborah Swanson"  writes:
> 
> > Peter Otten wrote, on January 08, 2017 3:01 AM
> >> 
> >> columnA = [record.A for record in records]
> >
> > This is very neat. Something like a list comprehension for named 
> > tuples?
> 
> Not something like - this *is* a list comprehension - it 
> creates a list of named tuples.
> 
> The thing you iterate over within the comprehension can be 
> any iterator. (Of course you're going to run into problems if 
> you try to construct a list from an infinite iterator.)

Thanks Paul. I've been meaning to spend some time getting to thoroughly
know list comprehensions for awhile now, but I keep running into so many
new things I just haven't gotten to it. I thought it looked like one,
but I hedged my wording because I wasn't sure.  Infinite iterators
definitely sound like something to remember!

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Using sudo with pip3?

2017-01-08 Thread Hans-Peter Jansen
On Samstag, 7. Januar 2017 19:07:55 Clint Moyer wrote:
> I would lightly advise against, assuming both Pip and your package
> manager are trying to accomplish nearly the same thing. Stick with
> updating through the repo.
> 
> If you find that the version your OS provides is out-of-date compared
> to what's on PyPi or Github, then you might want to remove from your
> OS and re-install through Pip, for those discrete cases. That's the
> platform agnostic route.

Or take the ninja way, I do:

Build all packages, you want (updated) for your distribution:

https://build.opensuse.org/project/monitor/home:frispete:python
https://build.opensuse.org/project/monitor/home:frispete:python3

The red labels are reminders...

SCR,
Pete
-- 
https://mail.python.org/mailman/listinfo/python-list


RE: Grumpy: Python to Go compiler

2017-01-08 Thread Deborah Swanson
Steven D'Aprano wrote, on January 07, 2017 11:37 PM
> 
> Grumpy, an experimental project from Google, transpiles 
> Python code into Go, allowing Python programs to be compiled 
> and run as static binaries using the Go toolchain.
> 
> 
> 
http://www.infoworld.com/article/3154624/application-development/google-
boosts-python-by-turning-it-into-go.html
>
>
>-- 
>Steven
>"Ever since I learned about confirmation bias, I've been seeing 
>it everywhere." - Jon Ronson

Interesting online resource, if you can stomach contact with Google.
I'll spare you the diatribe of all my beefs with Google (haha, unless
you ask). But this is a potentially useful tool to know about.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Grumpy: Python to Go compiler

2017-01-08 Thread Tim Daneliuk
On 01/08/2017 06:18 PM, Deborah Swanson wrote:
> (haha, unless
> you ask)

C'mon, go for it ... there hasn't been a good rant here in
4 or 5 minutes ...


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Search a sequence for its minimum and stop as soon as the lowest possible value is found

2017-01-08 Thread Antonio Caminero Garcia
On Friday, January 6, 2017 at 6:04:33 AM UTC-8, Peter Otten wrote:
> Example: you are looking for the minimum absolute value in a series of 
> integers. As soon as you encounter the first 0 it's unnecessary extra work 
> to check the remaining values, but the builtin min() will continue.
> 
> The solution is a minimum function that allows the user to specify a stop 
> value:
> 
> >>> from itertools import count, chain
> >>> stopmin(chain(reversed(range(10)), count()), key=abs, stop=0)
> 0
> 
> How would you implement stopmin()?
> 
> Currently I raise an exception in the key function:
> 
> class Stop(Exception):
> pass
> 
> def stopmin(items, key, stop):
> """
> >>> def g():
> ... for i in reversed(range(10)):
> ... print(10*i)
> ... yield str(i)
> >>> stopmin(g(), key=int, stop=5)
> 90
> 80
> 70
> 60
> 50
> '5'
> """
> def key2(value):
> result = key(value)
> if result <= stop:
> raise Stop(value)
> return result
> try:
> return min(items, key=key2)
> except Stop as stop:
> return stop.args[0]

This is the simplest version I could come up with. I also like the classic 100% 
imperative, but it seems that is not trendy between the solutions given :D.

you can test it here https://repl.it/FD5A/0
source code:

from itertools import accumulate

# stopmin calculates the greatest lower bound (infimum). 
# https://upload.wikimedia.org/wikipedia/commons/0/0a/Infimum_illustration.svg 

def takeuntil(pred, seq):
  for item in seq:
yield item
if not pred(item):
  break

def stopmin(seq, stop=0):
  drop_ltstop = (item for item in seq if item >= stop)
  min_gen = (min_ for min_ in accumulate(drop_ltstop, func=min))
  return list(takeuntil(lambda x: x!= stop, min_gen))[-1]

seq = [1, 4, 7, -8, 0, 7, -8, 9] # 0 just until zero is generated
seq = [1, 4, 7, -8, 7, -8, 9] # 1 the entire sequence is generated

print(stopmin(seq, stop=0))
-- 
https://mail.python.org/mailman/listinfo/python-list


RE: Grumpy: Python to Go compiler

2017-01-08 Thread Deborah Swanson
Tim Daneliuk wrote, on January 08, 2017 4:49 PM
> 
> On 01/08/2017 06:18 PM, Deborah Swanson wrote:
> > (haha, unless
> > you ask)
> 
> C'mon, go for it ... there hasn't been a good rant here in
> 4 or 5 minutes ...

Oh hell. (How do I tell him I was up til 8am this morning, only got a
few hours sleep, and I'm just too pookie now to deliver a decent rant on
all the ways Google is truly evil.  Don't have to, just did.)

Besides, I'm rewriting code this afternoon and really want to see how
much better it is when I'm done.

-- 
https://mail.python.org/mailman/listinfo/python-list


RE: Using namedtuples field names for column indices in a list of lists

2017-01-08 Thread Steven D'Aprano
On Sunday 08 January 2017 20:53, Deborah Swanson wrote:

> Steven D'Aprano wrote, on January 07, 2017 10:43 PM
>> 
>> On Sunday 08 January 2017 16:39, Deborah Swanson wrote:
>> 
>> > What I've done so far:
>> > 
>> > with open('E:\\Coding projects\\Pycharm\\Moving\\Moving
>> 2017 in.csv',
>> > 'r') as infile:
>> > ls = list(csv.reader(infile))
>> > lst = namedtuple('lst', ls[0])
>> > 
>> > where 'ls[0]' is the header row of the csv, and it works perfectly
>> > well. 'lst' is a namedtuple instance with each of the
>> column titles as
>> > field names.
>> 
>> Are you sure? namedtuple() returns a class, not a list:
> 
> Yes. 'ls' is defined as 'list(csv.reader(infile))', so ls[0] is the
> first row from the csv, the header row. 'lst' is the namedtuple.
> 
> Perhaps what's puzzling you is that the way I've written it, the list of
> data and the namedtuple are disjoint, and that's the problem.

No, I'm pretty sure that's not the case. I don't have access to your CSV file, 
but I can simulate it:

ls = [['Location', 'Date', 'Price'],
  ['here', '1/1/17', '1234'],
  ['there', '1/1/17', '5678'],
  ['everywhere', '1/1/17', '9821']
  ]

from collections import namedtuple
lst = namedtuple('lst', ls[0])

print(type(lst))
print(lst)



If you run that code, you should see:





which contradicts your statement:

'lst' is a namedtuple instance with each of the column 
titles as field names.


and explains why you had to access the individual property method `fget`: you 
were accessing the *class object* rather than an actual named tuple instance.

The code you gave was:

lst.Location.fget(l)

where l was not given, but I can guess it was a row of the CSV file, i.e. an 
individual record. So:

- lst was the named tuple class, a subclass of tuple

- lst.Location returns a property object

- lst.Location.fget is the internal fget method of the property object.


I think Peter Otten has the right idea: create a list of records with something 
like this:


Record = namedtuple('Record', ls[0])
data = [Record(*row) for row in ls[1:])


or if you prefer Peter's version:

data = [Record._make(row) for row in ls[1:])


Half the battle is coming up with the right data structures :-)


-- 
Steven
"Ever since I learned about confirmation bias, I've been seeing 
it everywhere." - Jon Ronson

-- 
https://mail.python.org/mailman/listinfo/python-list


Temporary variables in list comprehensions

2017-01-08 Thread Steven D'Aprano
Suppose you have an expensive calculation that gets used two or more times in a 
loop. The obvious way to avoid calculating it twice in an ordinary loop is with 
a temporary variable:

result = []
for x in data:
tmp = expensive_calculation(x)
result.append((tmp, tmp+1))


But what if you are using a list comprehension? Alas, list comps don't let you 
have temporary variables, so you have to write this:


[(expensive_calculation(x), expensive_calculation(x) + 1) for x in data]


Or do you? ... no, you don't!


[(tmp, tmp + 1) for x in data for tmp in [expensive_calculation(x)]]


I can't decide whether that's an awesome trick or a horrible hack...


-- 
Steven
"Ever since I learned about confirmation bias, I've been seeing 
it everywhere." - Jon Ronson

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Temporary variables in list comprehensions

2017-01-08 Thread Chris Angelico
On Mon, Jan 9, 2017 at 2:53 PM, Steven D'Aprano
 wrote:
> [(tmp, tmp + 1) for x in data for tmp in [expensive_calculation(x)]]
>
>
> I can't decide whether that's an awesome trick or a horrible hack...

A horrible hack on par with abusing a recursive function's arguments
for private variables. Much better would be to refactor the append
part:

def this_and_one(value):
return value, value + 1

[this_and_one(expensive_calculation(x)) for x in data]

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Temporary variables in list comprehensions

2017-01-08 Thread Steven D'Aprano
On Monday 09 January 2017 15:09, Chris Angelico wrote:

> On Mon, Jan 9, 2017 at 2:53 PM, Steven D'Aprano
>  wrote:
>> [(tmp, tmp + 1) for x in data for tmp in [expensive_calculation(x)]]
>>
>>
>> I can't decide whether that's an awesome trick or a horrible hack...
> 
> A horrible hack on par with abusing a recursive function's arguments
> for private variables. 

What's wrong with that? That's a perfectly legitimate technique. I prefer to 
hide it behind a private function rather than expose it in a public interface:

# instead of this
def recursive(arg, _internal=None):
"""Recursive function. Don't supply the _internal argument."""
...
return recursive(arg-1, spam)


# I usually prefer this
def recursive(arg):
"""Recursive function."""
return _recursive(arg, spam)

def _recursive(arg, internal):
...


but that's just polishing the code.



> Much better would be to refactor the append
> part:
> 
> def this_and_one(value):
> return value, value + 1

I wouldn't call that "much better". Requiring an extra function defeats the 
purpose of using a list comp, and it doesn't scale well for multiple list comps 
each of which needs a different helper function:


def this_and_one(value):
return value, value + 1

def this_less_one_and_this_plus_one_and_this(value):
return value - 1, value + 1, value

def this_and_that_or_something(value):
return value, value.that() or something

def extract_value(value):
return spam[value] or ham[value] or eggs[value]


and so on. Helper functions are good. Helper functions that are only used 
*once* are a code smell. *LOTS* of helper functions that are only used once are 
a sign that something is horrible, and it might just be your language...



-- 
Steven
"Ever since I learned about confirmation bias, I've been seeing 
it everywhere." - Jon Ronson

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Temporary variables in list comprehensions

2017-01-08 Thread Chris Angelico
On Mon, Jan 9, 2017 at 3:49 PM, Steven D'Aprano
 wrote:
> Helper functions are good. Helper functions that are only used
> *once* are a code smell. *LOTS* of helper functions that are only used once 
> are
> a sign that something is horrible, and it might just be your language...

Agreed, but with a toy example like you posted, it's impossible to say
which is happening :)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Temporary variables in list comprehensions

2017-01-08 Thread Rustom Mody
On Monday, January 9, 2017 at 10:19:31 AM UTC+5:30, Steven D'Aprano wrote:
> On Monday 09 January 2017 15:09, Chris Angelico wrote:
> 
> > On Mon, Jan 9, 2017 at 2:53 PM, Steven D'Aprano wrote:
> >> [(tmp, tmp + 1) for x in data for tmp in [expensive_calculation(x)]]
> >>
> >>
> >> I can't decide whether that's an awesome trick or a horrible hack...
> > 
> > A horrible hack on par with abusing a recursive function's arguments
> > for private variables. 
> 
> What's wrong with that? That's a perfectly legitimate technique. I prefer to 
> hide it behind a private function rather than expose it in a public interface:
> 
> # instead of this
> def recursive(arg, _internal=None):
> """Recursive function. Don't supply the _internal argument."""
> ...
> return recursive(arg-1, spam)
> 
> 
> # I usually prefer this
> def recursive(arg):
> """Recursive function."""
> return _recursive(arg, spam)
> 
> def _recursive(arg, internal):
> ...
> 
> 
> but that's just polishing the code.
> 
> 
> 
> > Much better would be to refactor the append
> > part:
> > 
> > def this_and_one(value):
> > return value, value + 1
> 
> I wouldn't call that "much better". Requiring an extra function defeats the 
> purpose of using a list comp, and it doesn't scale well for multiple list 
> comps 

+1

Id call it (your original) neither an awesome trick nor a horrible hack — just 
a neat workaround for an obvious lacuna

As for Chris' solution there is a simple test to see whether it's worth it:
Does the function name make sense? If yes then the subexpression refactored-
into-a-function is probably fine. If not the kludgyness shows

[Im assuming the real usage is something else and your question is a highly
sscce-ed version]
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Python for WEB-page !?

2017-01-08 Thread Eric S. Johansson
On 1/5/2017 7:48 PM, Michael Torrie wrote:
> While Python can do that, using a web framework to process HTTP requests
> and generate HTML to display in the browser, I don't believe Python is
> the appropriate language for the task at hand.  Most web sites that do
> interactive formula calculations like you describe do it all in the
> browser using Javascript.  No need to have a web server do all that
> heavy lifting at all.  A simple html file would contain everything you need.
>
> Even if you want to use Python to generate the web page and process
> events, you'll still have to master Javascript at some point to make the
> webpages more interactive.

There are a few implementations of Python that generate code that can
run the browser. I'm currently using brython and its significantly
easier than struggling with JavaScript. It's not perfect by any means,
it has its own quirks and bugs but the developer is very responsive, the
product is getting better every month and I like to see the Python
community give it a bit more love

-- 
https://mail.python.org/mailman/listinfo/python-list


RE: Using namedtuples field names for column indices in a list of lists

2017-01-08 Thread Deborah Swanson
Steven D'Aprano wrote, on January 07, 2017 10:43 PM
> 
> On Sunday 08 January 2017 16:39, Deborah Swanson wrote:
> 
> The recommended way is with the _replace method:
> 
> py> instance._replace(A=999)
> Record(A=999, B=20, C=30)
> py> instance._replace(A=999, C=888)
> Record(A=999, B=20, C=888)
> 
> -- 
> Steven
> "Ever since I learned about confirmation bias, I've been seeing 
> it everywhere." - Jon Ronson

instance._replace(A=999) works perfectly, and editting my existing
assignment statements was really easy.  Thanks - a lot.

-- 
https://mail.python.org/mailman/listinfo/python-list


RE: Using namedtuples field names for column indices in a list of lists

2017-01-08 Thread Deborah Swanson
Peter Otten wrote, on January 08, 2017 5:21 AM
> 
> Deborah Swanson wrote:
> 
> > Peter Otten wrote, on January 08, 2017 3:01 AM
>  
> Personally I would recommend against mixing data (an actual location)
and 
> metadata (the column name,"Location"), but if you wish my code can be 
> adapted as follows:
> 
> infile = open("dictreader_demo.csv")
> rows = csv.reader(infile)
> fieldnames = next(rows)
> Record = namedtuple("Record", fieldnames)
> records = [Record._make(fieldnames)]
> records.extend(Record._make(row) for row in rows)

Works like a charm. I stumbled a bit changing all my subscripted
variables to namedtuples and rewriting the inevitable places my code
that didn't work the same. But actually it was fun, especially deleting
all the sections and variables I no longer needed. And it executes
correctly now too - with recognizable fieldnames instead of my quirky
2-letter code subscripts.  All in all a huge win!

I do have two more questions.

1) I have a section that loops through the sorted data, compares two
adjacent rows at a time, and marks one of them for deletion if the rows
are identical.

I'm using 

for i in range(len(records)-1):
r1 = records[i]
r2 = records[i+1]
if r1.xx = r2.xx:
.
.
and my question is whether there's a way to work with two adjacent rows
without using subscripts?  

Even better, to get hold of all the records with the same Description as
the current row, compare them all, mark all but the different ones for
deletion, and then resume processing the records after the last one?

2) I'm using mergesort. (I didn't see any way to sort a namedtuple in
the docs.) In the list version of my code I copied and inserted the 2
columns I wanted to sort by into the beginning of the list, and then
deleted them after the list was sorted. But just looking at records, I'm
not so sure that can easily be done. I remember your code to work with
columns of the data:

columnA = [record.A for record in records]

and I can see how that would get me columnA and columnB, but then is
there any better way to insert and delete columns in an existing
namedtuple than slicing? And I don't think you can insert or delete a
whole column while slicing.

Or maybe my entire approach is not the best. I know it's possible to do
keyed sorts, but I haven't actually written or used any. So I just
pulled a mergesort off the shelf and got what I wanted by inserting
copies of those 2 columns at the front, and then deleting them when the
sort was complete. Not exactly elegant, but it works.

Any suggestions would be most welcome. 

-- 
https://mail.python.org/mailman/listinfo/python-list


RE: Using namedtuples field names for column indices in a list of lists

2017-01-08 Thread Deborah Swanson
Steven D'Aprano wrote, on January 08, 2017 7:30 PM
> 
> On Sunday 08 January 2017 20:53, Deborah Swanson wrote:
> 
> > Steven D'Aprano wrote, on January 07, 2017 10:43 PM
> 
> No, I'm pretty sure that's not the case. I don't have access 
> to your CSV file, 
> but I can simulate it:
> 
> ls = [['Location', 'Date', 'Price'],
>   ['here', '1/1/17', '1234'],
>   ['there', '1/1/17', '5678'],
>   ['everywhere', '1/1/17', '9821']
>   ]
> 
> from collections import namedtuple
> lst = namedtuple('lst', ls[0])
> 
> print(type(lst))
> print(lst)
> 
> 
> 
> If you run that code, you should see:
> 
> 
> 
> 
> 
> which contradicts your statement:
> 
> 'lst' is a namedtuple instance with each of the column 
> titles as field names.

Yes, yes. In a careless moment I called a class an instance.

> and explains why you had to access the individual property 
> method `fget`: you 
> were accessing the *class object* rather than an actual named 
> tuple instance.

That code is deleted and long gone now, so I can't look at it in the
debugger, but yes, I'm pretty sure 'fget' is a class member.

> The code you gave was:
> 
> lst.Location.fget(l)
> 
> where l was not given, but I can guess it was a row of the 
> CSV file, i.e. an 
> individual record. So:
> 
> - lst was the named tuple class, a subclass of tuple
> 
> - lst.Location returns a property object
> 
> - lst.Location.fget is the internal fget method of the 
> property object.

And your point is?  Perhaps I didn't express myself in a way that you
could recognize, but I understood all of that before I wrote to you, and
attempted to convey that understanding to you. Obviously I failed, if
you now think I need a lesson in what's going on here.

> I think Peter Otten has the right idea: create a list of 
> records with something 
> like this:
> 
> 
> Record = namedtuple('Record', ls[0])
> data = [Record(*row) for row in ls[1:])
> 
> 
> or if you prefer Peter's version:
> 
> data = [Record._make(row) for row in ls[1:])
> 
> 
> Half the battle is coming up with the right data structures :-)

Can't and wouldn't disagree with any part of that!

> -- 
> Steven
> "Ever since I learned about confirmation bias, I've been seeing 
> it everywhere." - Jon Ronson

-- 
https://mail.python.org/mailman/listinfo/python-list