[Tutor] Playing with generators

avi.e.gross at gmail.com avi.e.gross at gmail.com
Wed Aug 10 15:44:36 EDT 2022


Leam,

Again, we have had some "trying to learn to do X in Python" questions here
before that make some of us suspicious for an assortment of reasons.

If we choose to answer, it is only possible to answer what we are told. If
you TELL us you want the key to be the first name, then that is what any
answer addresses. Consider adding COMMENTS that makes things clearer and
saying clearly that this is a simplified case and the actual key chosen may
be more complex.

In your case, you shared an extremely SIMPLE scenario where the Person
object contains NOTHING useful or new that the item in the list of
dictionaries did not already have. In my reply, the line I offered made use
of that fact as first name is already in the item being iterated on:

def make_peeps(data):
  return { datum.get('fname', 'missing'): Person(datum) for datum in data }

The point was that a simple comprehension (with no function call needed if
you prefer) would take your list of dictionaries and produce a dictionary or
Person objects.

Now if you flesh out Person and add more data and give it internal state
including functions of various kinds, sure, the key you compose may need to
await creating the Person before you can extract the key you need. You DID
NOT ASK FOR ANYTHING other than your example and my answer remains valid in
that scenario.

But no matter what more complex scenario you want, I suggest you consider
writing your iterator in the more formal way as:

Here is some code that describes my thought process:

# Function that iterates on a list of dictionaries
# producing another dictionary containing an object derived
# from each initial dictionary of class Person.
def my_iterator(data):

     # Loop on each dict item in the list:
     for old_dict in data:
          
          # Create a Person
          Lonely = Person(item)

          # Ask the object what key is appropriate
          # for use as a unique identifier for this
          # instance as a value in another dictionary.
          # This assumes some method of getting it such
          # as a method in the class or anything else. 
          key = Person.keyed_up()
          
          # Return a dictionary containing the key/value
          # pair, OR ANYTHING ELSE, with a yield.
          yield {key : Person }


You can customize something along those lines to return one dictionary at a
time, and do some bulletproofing. Whatever needs an iterator can, if
properly used, keep invoking the darn function to get what it needs or stop
when it has enough. And the caller can indeed build up a list of these
things or add them to a dictionary and so on.

Your question may be more along these lines.

Using a comprehension, can you make an object AND access a method that makes
a key at the same time as in:

{ {obj.get_key(): obj(datum)} for datum in data }

Or something similar. 

Who knows? It might take a bit of thinking.

My daughter just got engaged and it is going to soak up a lot of my time, so
...


-----Original Message-----
From: Tutor <tutor-bounces+avi.e.gross=gmail.com at python.org> On Behalf Of
Leam Hall
Sent: Wednesday, August 10, 2022 2:34 PM
To: 'python tutor' <Tutor at python.org>
Subject: Re: [Tutor] Playing with generators

Hello Avi!

I apologize for the use of "peeps"; I try to avoid slang terms when talking
to an international group. My brain didn't wake up this morning, and I
missed fixing that.

The task is to learn generators, and I tried to minimize the code to focus
on my main question, "can a generator return a key and an object as a value,
such that the key is an attribute of the value object?" My code, while it
needs work, proves that it the generator can.

I'm not sure that your code line meets that question:  return {
datum.get('fname', 'missing'): Person(datum) for datum in data }
Specifically, it seems to be using 'fname' from datum, not from the object.
As you said, the first name is not a good key, the object will eventually
create a better one from the data provided. I used fname in the example to
keep the code sample short, but to show that I had actually done some work
on the question.

Leam
	
On 8/10/22 10:08, avi.e.gross at gmail.com wrote:
> Not sure if this question is another IQ test from someone! LOL!
> 
> Overview, once I struggled with your naming is that you have data in a 
> dictionary format and a list of such items. You want to convert each 
> dictionary to an object of Class Person and then instead of a list of 
> Person objects want to make a dictionary of Person objects as values 
> with keys specific to that object. So far, seems easy enough but you 
> have an amorphous question about wanting to use generators as an exercise.
> 
> Generally, a generator does not make everything at once but keeps 
> returning more as it is iterated. It can return a next item or it can 
> return a growing item, so what exactly is your deliverable here? Do 
> you want a generator that makes one Person at a time as needed, or one 
> dictionary containing a person with a key at a time, or a growing 
> dictionary of such dictionaries that is lengthened by one each time?
> 
> As a start, I  just want to make a suggestion so your code is a tad 
> easier to understand.
> 
> Your make_person() function does not make A person but a list of 
> objects of class Person. Consider naming it make_persons() to indicate 
> that. Yes, it uses a generator expression and arguably makes one at a 
> time. But the result from outside seems more naturally, to me, to be a 
> generator that makes persons.
> 
> Your uses of the name "peeps" took a while to make sense and now seems 
> to be a slang way of saying "peoples" and may be intuitively obvious 
> to you but made me start thinking of other things to do than read your 
> uncommented code that made me have to figure out what it was you were
doing.
> 
> You seem to want to make a dictionary of People as values indexed by 
> first name. First names tend to not be unique.  So not an optimal key 
> unless you don't care or have some guarantees.
> 
> But if I am getting your question, and I bet I am not, you want to 
> know if there is a briefer or simpler way to consolidate what you are 
> doing. Will this work?
> 
> def make_peeps(data):
>      return { datum.get('fname', 'missing'): Person(datum) for datum 
> in data }
> 
> The above just needs your list of dictionaries, stored in "data" and 
> uses a dictionary comprehension to make the entire dictionary of 
> Person objects you seem to want. But are you requiring this be done in 
> some kind of generator for a practical reason or just as an exercise?
> 
> One obvious way to do it is with a generator function with an explicit 
> yield. Put your loop in there and yield whatever you want until done. 
> Or do you insist on using a generator expression way?
> 
> 
> 
> -----Original Message-----
> From: Tutor <tutor-bounces+avi.e.gross=gmail.com at python.org> On Behalf 
> Of Leam Hall
> Sent: Wednesday, August 10, 2022 7:33 AM
> To: python tutor <Tutor at python.org>
> Subject: [Tutor] Playing with generators
> 
> I'm wondering if there's a way to combine "make_person" with the 
> generator in "for fname, peep in". Even if it can be done, should it 
> be done? Or would the code be overly complex?
> 
> The goal is to parse a group of data, and create a dict where the 
> value is an object created from the data, and the key is an attribute 
> of the object itself.
> 
> 
> class Person():
>       def __init__(self, data = {}):
>           self.fname = data.get('fname', 'fred')
>           self.lname = data.get('lname', 'frank')
> 
> data = [
>       { 'fname':'Wilbur', 'lname':'Lefron' },
>       { 'fname':'Al', 'lname':'Lefron' },
>       { 'fname':'Jo', 'lname':'Franco' },
>       { 'fname':'Mon', 'lname':'Pascal' },
>       { 'fname':'Gray', 'lname':'Webb-Marston'},
>       ]
> 
> def make_person(data):
>       ps = ( Person(d) for d in data)
>       return ps
>           
> peeps = {}
> 
> for fname, peep in ( (p.fname, p) for p in make_person(data) ):
>       peeps[fname] = peep
> 
> 
> for person in peeps.values():
>       print(person.lname)
> 

-- 
Automation Engineer        (reuel.net/resume)
Scribe: The Domici War     (domiciwar.net)
General Ne'er-do-well      (github.com/LeamHall)
_______________________________________________
Tutor maillist  -  Tutor at python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor



More information about the Tutor mailing list