mahmoud / glom

☄️ Python's nested data operator (and CLI), for all your declarative restructuring needs. Got data? Glom it! ☄️
https://glom.readthedocs.io
Other
1.89k stars 61 forks source link

T doesn't change context when called in different scopes #201

Open kurka opened 3 years ago

kurka commented 3 years ago

I am trying to get all elements from nested lists of classes, using glom.

I have the following definitions:

class U:
    def __init__(self, c):
        self.as = [A(cc) for cc in c]

class A:
     def __init__(self, v):
         self.v = v

target = [U([1,2,3]), U([4,5,6])]

that is, U stores a list of A classes, each storing a value (v) as attribute.

I am trying to list all values for the nested classes A with the expression:

glom(target, [T.as, [T.v]])

However, instead of a list of lists of v, I get:

[[<__main__.A at 0x7fd1e7b6cdf0>,
  <__main__.A at 0x7fd1e7b6cbe0>,
  <__main__.A at 0x7fd1e7b6c6d0>],
 [<__main__.A at 0x7fd1e7b58460>,
  <__main__.A at 0x7fd1e7b58400>,
  <__main__.A at 0x7fd1e7b58910>]]

It seems that the second call for T (T.v) has no effect, and what is returned is the value of the first T call (T.as). Is this a bug, or something expected?

If that's expected, what is the right way to access nested class objects, and have different contexts for T on a glom spec?

kurtbrose commented 3 years ago

lists ignore everything after the first element -- if you want them to be executed one after the other you'll need a tuple in the list

glom(target, [(T.as, [T.v])])

then you'll probably want a flatten at the end so you don't get [[1, 2, 3], [4, 5, 6] but [1, 2, 3, 4, 5, 6]

glom(target, ([(T.as, [T.v])], Flatten()))
kurka commented 3 years ago

Many thanks, @kurtbrose, that's exactly the solution I needed!

But I was a bit confused with the statement "lists ignore everything after the first element". Why is that the case? Is this documented somewhere?

I indeed noticed that I could write any invalid expression in the second element of the list and it wouldn't have any effect... Shouldn't at least a warning be raised if a multi element list is passed in a spec?