• Popping key causes dict derived from object to revert to object

    From Loris Bennett@21:1/5 to All on Thu Mar 21 10:56:42 2024
    Hi,

    I am using SQLAlchemy to extract some rows from a table of 'events'.
    From the call to the DB I get a list of objects of the type

    sqlalchemy.orm.state.InstanceState

    I would like to print these rows to the terminal using the 'tabulate'
    package, the documentation for which says

    The module provides just one function, tabulate, which takes a list of
    lists or another tabular data type as the first argument, and outputs
    a nicely formatted plain-text table

    So as I understand it, I need to convert the InstanceState-objects to,
    say, dicts, in order to print them. However I also want to remove one
    of the keys from the output and assumed I could just pop it off each
    event dict, thus:

    event_dicts = [vars(e) for e in events]
    print(type(event_dicts[0]))
    event_dicts = [e.pop('_sa_instance_state', None) for e in event_dicts]
    print(type(event_dicts[0]))

    However, this prints

    <class 'dict'>
    <class 'sqlalchemy.orm.state.InstanceState'>

    If I comment out the third line, which pops the unwanted key, I get

    <class 'dict'>
    <class 'dict'>

    Why does popping one of the keys cause the elements of the list to
    revert back to their original class?

    Cheers,

    Loris

    --
    This signature is currently under constuction.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dieter.maurer@online.de@21:1/5 to Loris Bennett on Thu Mar 21 17:21:52 2024
    Loris Bennett wrote at 2024-3-21 10:56 +0100:
    ...
    So as I understand it, I need to convert the InstanceState-objects to,
    say, dicts, in order to print them. However I also want to remove one
    of the keys from the output and assumed I could just pop it off each
    event dict, thus:

    event_dicts = [vars(e) for e in events]
    print(type(event_dicts[0]))
    event_dicts = [e.pop('_sa_instance_state', None) for e in event_dicts]
    print(type(event_dicts[0]))

    However, this prints

    <class 'dict'>

    `vars` typically returns a `dict`.

    <class 'sqlalchemy.orm.state.InstanceState'>
    This is what you have popped.

    If I comment out the third line, which pops the unwanted key, I get
    Then you do not change `event_dicts`.

    You problem likely is:
    `pop` does not return the `dict` after the removal of a key
    but the removed value.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mark Bourne@21:1/5 to Loris Bennett on Thu Mar 21 21:09:53 2024
    Loris Bennett wrote:
    Hi,

    I am using SQLAlchemy to extract some rows from a table of 'events'.
    From the call to the DB I get a list of objects of the type

    sqlalchemy.orm.state.InstanceState

    I would like to print these rows to the terminal using the 'tabulate' package, the documentation for which says

    The module provides just one function, tabulate, which takes a list of
    lists or another tabular data type as the first argument, and outputs
    a nicely formatted plain-text table

    So as I understand it, I need to convert the InstanceState-objects to,
    say, dicts, in order to print them. However I also want to remove one
    of the keys from the output and assumed I could just pop it off each
    event dict, thus:

    event_dicts = [vars(e) for e in events]
    print(type(event_dicts[0]))
    event_dicts = [e.pop('_sa_instance_state', None) for e in event_dicts]
    print(type(event_dicts[0]))

    vars() returns the __dict__ attribute of the object. It may not be a
    good idea to modify that dictionary directly (it will also affect the
    object), although it might be OK if you're not going to do anything else
    with the original objects. To be safer, you could copy the event objects:
    event_dicts = [dict(vars(e)) for e in events]
    or:
    event_dicts = [vars(e).copy()]

    However, this prints

    <class 'dict'>
    <class 'sqlalchemy.orm.state.InstanceState'>

    If I comment out the third line, which pops the unwanted key, I get

    <class 'dict'>
    <class 'dict'>

    Why does popping one of the keys cause the elements of the list to
    revert back to their original class?

    As Dieter pointed out, the main problem here is that pop() returns the
    value removed, not the dictionary with the rest of the values. You
    probably want something more like:
    for e in event_dicts:
    del e['_sa_instance_state']
    (There's not really any point popping the value if you're not going to
    do anything with it - just delete the key from the dictionary)

    --
    Mark.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Loris Bennett@21:1/5 to Mark Bourne on Fri Mar 22 08:58:28 2024
    Mark Bourne <nntp.mbourne@spamgourmet.com> writes:

    Loris Bennett wrote:
    Hi,
    I am using SQLAlchemy to extract some rows from a table of 'events'.
    From the call to the DB I get a list of objects of the type
    sqlalchemy.orm.state.InstanceState
    I would like to print these rows to the terminal using the
    'tabulate'
    package, the documentation for which says
    The module provides just one function, tabulate, which takes a
    list of
    lists or another tabular data type as the first argument, and outputs
    a nicely formatted plain-text table
    So as I understand it, I need to convert the InstanceState-objects
    to,
    say, dicts, in order to print them. However I also want to remove one
    of the keys from the output and assumed I could just pop it off each
    event dict, thus:
    event_dicts = [vars(e) for e in events]
    print(type(event_dicts[0]))
    event_dicts = [e.pop('_sa_instance_state', None) for e in event_dicts] >> print(type(event_dicts[0]))

    vars() returns the __dict__ attribute of the object. It may not be a
    good idea to modify that dictionary directly (it will also affect the object), although it might be OK if you're not going to do anything
    else with the original objects. To be safer, you could copy the event objects:
    event_dicts = [dict(vars(e)) for e in events]
    or:
    event_dicts = [vars(e).copy()]

    Thanks for making this clear to me. However, in the end I actually
    decided to use the list comprehension without either 'dict()' or
    'vars(). Instead I just select the keys I want and so don't need to pop
    the unwanted key later and can simultaneously tweak the names of the
    key for better printing to the terminal.

    However, this prints
    <class 'dict'>
    <class 'sqlalchemy.orm.state.InstanceState'>
    If I comment out the third line, which pops the unwanted key, I get
    <class 'dict'>
    <class 'dict'>
    Why does popping one of the keys cause the elements of the list to
    revert back to their original class?

    As Dieter pointed out, the main problem here is that pop() returns the
    value removed, not the dictionary with the rest of the values. You
    probably want something more like:
    for e in event_dicts:
    del e['_sa_instance_state']
    (There's not really any point popping the value if you're not going to
    do anything with it - just delete the key from the dictionary)

    Yes, I was mistakenly thinking that the popping the element would leave
    me with the dict minus the popped key-value pair. Seem like there is no
    such function.

    Cheers,

    Loris

    --
    This signature is currently under constuction.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Loris Bennett@21:1/5 to Grant Edwards on Mon Mar 25 07:56:16 2024
    Grant Edwards <grant.b.edwards@gmail.com> writes:

    On 2024-03-22, Loris Bennett via Python-list <python-list@python.org> wrote:

    Yes, I was mistakenly thinking that the popping the element would
    leave me with the dict minus the popped key-value pair.

    It does.

    Indeed, but I was thinking in the context of

    dict_list = [d.pop('a') for d in dict_list]

    and incorrectly expecting to get a list of 'd' without key 'a', instead
    of a list of the 'd['a]'.

    Seem like there is no such function.

    Yes, there is. You can do that with either pop or del:

    >>> d = {'a':1, 'b':2, 'c':3}
    >>> d
    {'a': 1, 'b': 2, 'c': 3}
    >>> d.pop('b')
    2
    >>> d
    {'a': 1, 'c': 3}


    >>> d = {'a':1, 'b':2, 'c':3}
    >>> del d['b']
    >>> d
    {'a': 1, 'c': 3}

    In both cases, you're left with the dict minus the key/value pair.

    In the first case, the deleted value printed by the REPL because it
    was returned by the expression "d.pop('b')" (a method call).

    In the second case is no value shown by the REPL because "del d['b']"
    is a statement not an expression.

    Thanks for pointing out 'del'. My main problem, however, was failing to realise that the list comprehension is populated by the return value of
    the 'pop', not the popped dict.

    Cheers,

    Loris

    --
    This signature is currently under constuction.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Loris Bennett@21:1/5 to avi.e.gross@gmail.com on Mon Mar 25 07:45:15 2024
    <avi.e.gross@gmail.com> writes:

    Loris wrote:

    "Yes, I was mistakenly thinking that the popping the element would leave
    me with the dict minus the popped key-value pair. Seem like there is no
    such function."

    Others have tried to explain and pointed out you can del and then use the changed dict.

    But consider the odd concept of writing your own trivial function.

    def remaining(adict, anitem):
    _ = adict.pop(anitem)
    # alternatively duse del on dict and item
    return adict


    remaining({"first": 1, "second": 2, "third": 3}, "second")
    {'first': 1, 'third': 3}


    Or do you want to be able to call it as in dict.remaining(key) by
    subclassing your own variant of dict and adding a similar method?

    No, 'del' does indeed do what I wanted, although I have now decided I
    want something else :-) Nevertheless it is good to know that 'del'
    exists, so that I don't have to reinvent it.

    Cheers,

    Loris

    --
    This signature is currently under constuction.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Loris Bennett@21:1/5 to Michael F. Stemper on Mon Mar 25 15:58:39 2024
    "Michael F. Stemper" <michael.stemper@gmail.com> writes:

    On 25/03/2024 01.56, Loris Bennett wrote:
    Grant Edwards <grant.b.edwards@gmail.com> writes:

    On 2024-03-22, Loris Bennett via Python-list <python-list@python.org> wrote:

    Yes, I was mistakenly thinking that the popping the element would
    leave me with the dict minus the popped key-value pair.

    It does.
    Indeed, but I was thinking in the context of
    dict_list = [d.pop('a') for d in dict_list]
    and incorrectly expecting to get a list of 'd' without key 'a',
    instead
    of a list of the 'd['a]'.
    I apologize if this has already been mentioned in this thread, but are
    you aware of "d.keys()" and "d.values"?

    d = {}
    d['do'] = 'a deer, a female deer'
    d['re'] = 'a drop of golden sunshine'
    d['mi'] = 'a name I call myself'
    d['fa'] = 'a long, long way to run'
    d.keys()
    ['fa', 'mi', 'do', 're']
    d.values()
    ['a long, long way to run', 'a name I call myself', 'a deer, a female deer', 'a drop of golden sunshine']


    Yes, I am, thank you. However, I didn't want either the keys or the
    values. Instead I wanted to remove a key within a list comprehension.

    Cheers,

    Loris

    PS: "a drop of golden *sun*" - rhymes with "a long, long way to run"


    --
    This signature is currently under constuction.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jon Ribbens@21:1/5 to Loris Bennett on Mon Mar 25 15:19:17 2024
    On 2024-03-25, Loris Bennett <loris.bennett@fu-berlin.de> wrote:
    "Michael F. Stemper" <michael.stemper@gmail.com> writes:

    On 25/03/2024 01.56, Loris Bennett wrote:
    Grant Edwards <grant.b.edwards@gmail.com> writes:

    On 2024-03-22, Loris Bennett via Python-list <python-list@python.org> wrote:

    Yes, I was mistakenly thinking that the popping the element would
    leave me with the dict minus the popped key-value pair.

    It does.
    Indeed, but I was thinking in the context of
    dict_list = [d.pop('a') for d in dict_list]
    and incorrectly expecting to get a list of 'd' without key 'a',
    instead
    of a list of the 'd['a]'.
    I apologize if this has already been mentioned in this thread, but are
    you aware of "d.keys()" and "d.values"?

    d = {}
    d['do'] = 'a deer, a female deer'
    d['re'] = 'a drop of golden sunshine'
    d['mi'] = 'a name I call myself'
    d['fa'] = 'a long, long way to run'
    d.keys()
    ['fa', 'mi', 'do', 're']
    d.values()
    ['a long, long way to run', 'a name I call myself', 'a deer, a female deer', 'a drop of golden sunshine']


    Yes, I am, thank you. However, I didn't want either the keys or the
    values. Instead I wanted to remove a key within a list comprehension.

    Do you mean something like:

    [my_dict[key] for key in my_dict if key != 'a']

    ?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)