1

Is there any clean way to get a list item's field in a for loop, i.e. directly iterating over the field values without explicitly getting it in the loop itself. Example:

from collections import namedtuple

Person = namedtuple("Person", ["name", "age"])
p1 = Person("Bob", 42)
p2 = Person("Sam", 19)
l = [p1, p2]
for p in l:
    p_name = p.name
    print(p_name)

I would like to get the parameter p_name from the for declaration. The use of tuples is only for example, the solution should work also for objects and preferably for dict

antonpuz
  • 3,256
  • 4
  • 25
  • 48
  • 1
    `for p_name in (p.name for p in l): print(p_name)`? – Andreas May 04 '21 at 09:06
  • @Andreas very nice that you've used generator expression, I'm not sure its cleaner than simply assigning it in the next line (I like not having the variable p in your solution). If no direct solution exist this would probably be the best you could do – antonpuz May 04 '21 at 09:13
  • I don't see any way this can be done - in fact, why would you want to do so ? Sounds to me like an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) … – TheEagle May 04 '21 at 09:17
  • @Programmer say you only need p.name for a calculation in a for loop, say it appears many times in the for loop so you would assign it to a variable, now you have 2 variables in the loop p and p_name where only one is really needed. this harms readability and adds unnecessary steps to the flow, could result in bugs where p would be used instead of p_name – antonpuz May 04 '21 at 09:22
  • I think OP just wants this as a convenience feature, similar to javascript's object destructuring. Perhaps it could be useful in writing more succinct code - but this is not something available in python, yet. As a side note, pattern matching with `match` in python 3.10 offers a somewhat similar feature - but isn't a construct available in for loops. – Chase May 04 '21 at 09:22
  • Okay, then, your question should rather be about "Is there a way to get an object's attribute rather than the object itself when assigning it to a variable ?" – TheEagle May 04 '21 at 09:24
  • @Programmer I'm looking specifically for something that would work with the for loops. The phrase `object's attribute` could be used to improve clarity, thx for that comment – antonpuz May 04 '21 at 09:27

1 Answers1

2

Since you're using a namedtuple, which is still just a tuple - you can use tuple unpacking-

for p_name, _ in l:
    print(p_name)

Edit: Just to make it clear in this answer - there is currently no way to directly do object destructuring/unpacking in the init section of a for loop. The only unpacking construct supported is tuple unpacking.

For ordered objects, you can get a tuple (actually a list) of all values using dir (or some other method/function specific to the object) and use tuple unpacking on them.

You can, however, approach this as a multi step process - by mapping a function that extracts only the fields you want into a tuple, over the iterable - and then iterating through the result and using tuple unpacking. Use lazy generators to do this efficiently. This is the technique mentioned by @Andreas in a comment, namely-

for p_name in (p.name for p in l):
  print(p_name)

You can do the same for any object-

for pfoo, pbar, pbaz in ((p.foo, p.bar, p.baz) for p in l):
  print(pfoo, pbar, pbaz)
Chase
  • 5,315
  • 2
  • 15
  • 41
  • I've used namedtuple as an example, I'm looking for a solution which could expand to objects, and also I don't want to restrict the structure – antonpuz May 04 '21 at 09:14
  • @Anton.P python does not have object/dict unpacking yet unfortunately. In the specific case of `for` loops, the only unpacking construct supported is tuple unpacking. I assume you're looking for something akin to javascript object destructuring. – Chase May 04 '21 at 09:16
  • Though I should mention that the concept of "dict unpacking" is available (using the `**` operator), but it is vastly different than tuple unpacking and is not usable in `for` loops. – Chase May 04 '21 at 09:19
  • What about using dir (such as suggested [here](https://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class-in-python)) ? – DonKnacki May 04 '21 at 09:56
  • @DonKnacki Already mentioned in my answer. – Chase May 04 '21 at 09:57