Skip to content
This repository has been archived by the owner on Feb 2, 2019. It is now read-only.

why does AttrMap return a tuple when a list is stored? #34

Open
gabyx opened this issue May 8, 2015 · 11 comments
Open

why does AttrMap return a tuple when a list is stored? #34

gabyx opened this issue May 8, 2015 · 11 comments

Comments

@gabyx
Copy link

gabyx commented May 8, 2015

from attrdict import AttrMap as mp
m=mp({"a":[1,2,3]})
m.a

return (1,2,3)

This sould not happen, right? Would be really good to fix this :-)
Thanks 👍

@gabyx
Copy link
Author

gabyx commented May 8, 2015

m["a"] by the way returns the list however

@zamoa
Copy link

zamoa commented Jul 28, 2015

AttrDict also return tuple
ex)
ad = AttrDict({'foo': ['bar']})
assert ad.foo == ('bar')
assert ad['foo'] == ['bar']

@jonathanstrong
Copy link

I started using this in a project, and now I regret it because of this behavior, which is completely fucked.

This is Python. You don't silently change the type of objects passed to a data structure!

Not to mention it's not even consistent.

>>> a = AttrDict()
>>> a.one = [1, 2, 3]
>>> type(a.one)
tuple
>>> type(a['one'])
list

my mistake for assuming something simple like this would have been executed without huge pitfalls.

@jeffkayser
Copy link

While I'm not sure what the justification is for this behavior by default, it's very easily worked-around. It takes longer to post a complaint on Github than to look at the method signatures to find out how to change the undesired behavior.

The constructors for AttrMap and AttrDefault take a sequence_type argument, which you just need to set to list:

>>> m = AttrMap(sequence_type=list)
>>> m.l = [1, 2, 3]
>>> m.l
[1, 2, 3]
>>> type(m.l)
<class 'list'>

Strangely, AttrDict doesn't take this parameter, but it's possible to change its behavior as well with a hack:

>>> d = AttrDict()
>>> d._setattr('_sequence_type', list)
>>> d.l = [1, 2, 3]
>>> d.l
[1, 2, 3]
>>> type(d.l)
<class 'list'>

@gabyx
Copy link
Author

gabyx commented Apr 11, 2016

Thanks so this might be solved

@H0R5E
Copy link

H0R5E commented Jul 21, 2016

I have a problem accessing an xarray.Dataset object which, when returned, is converted to an attrdict.dictionary.AttrDict.

I really want to suppress this behaviour.

@H0R5E
Copy link

H0R5E commented Jul 21, 2016

Its the _build method that changes the types so I have simply patched it like so:

class MyAttrDict(AttrDict):
    def _build(self, obj):
        return obj

This means that you can only access attributes to the first dot (no foo.bar.hello.world) but that is all I need and want.

@jonschull
Copy link

jeffkayser's solution is helpful for the special case, but the general problem remains:

  If you set the default sequence_type to list, empty tuples are silently converted to lists.  

This is a genuine bug.

@jonschull
Copy link

jeff Kayser's solution does not in fact workl
(neither does changing the the default in /attrdict/dictionary.py)
append silently fails:

d = AttrDict()
d._setattr('_sequence_type', list)
d.l = [1, 2, 3]
d.l
[1, 2, 3]
type(d.l)
d
AttrDict({'l': [1, 2, 3]})
d.l
[1, 2, 3]
d.l.append('x')
d.l
[1, 2, 3]

@jonathanstrong
Copy link

@jonschull
Copy link

Thanks jonathanStrong. Backatcha. It's new, so comments welcome.

#from attrdict import AttrDict
class AttrDict(dict): #http://code.activestate.com/recipes/576972-attrdict/;
def init(self, *a, **kw):
dict.init(self, *a, **kw)
self.dict = self

verbose=False
class AttrThing(AttrDict):
""" AttrThing does what AttrDict does
can return multiple elements
returns keys() and values() as lists to support indexing
does not turn lists into tuples (c.f., https://pypi.python.org/pypi/attrdict')
"""

def __call__(self, *args, **kwargs):
    #print('in __call__', args, kwargs)
    for k,v in kwargs.items(): #allow a(this='this', that='that') for existing object
        #self[k]=v
        self.__setattr__(k,v)
        
    if args:
        if len(args)==1: return self.__getitem__(args[0]) 
        
        ret=[] #but also field multiple requests and return answers as lists
        for arg in args:
            ret.append(self.__getitem__(arg))
        return ret

def keys(self):
       return list(super(AttrThing, self).keys())

def values(self):
    return list(super(AttrThing, self).values())

if name=='main':
a=AttrThing()
a(first='Can be initialized this way', second='See?')
print(a)
print()
#{'first': 'Can be initialized this way', 'second': 'See?'}

del a.first, a.second
a['this']='settable with bracket'
print(a)
print()
#{'this': 'settable with bracket'}

#like AttrDict
a.this='settable with dot'
print(a)
print()
#{'this': 'settable with dot'}


#like AttrDict, gettable 3 ways 
a.this='THIS'
print(a.this, a['this'], a('this'), '\t\t', a.this==a['this']==a('this'), "\t\t Note:  a.this == a['this'] == a(this)")
print()
#THIS THIS THIS 		 True 		 Note:  a.this == a['this'] == a(this)

#unlike AttrDict, keys() and values() are lists
print(type(a.keys()), type(a.values()), a.keys()[0], a.values()[0], '\n\t\t Note: Return keys() and values() as lists to allow indexing via a.keys()[0]')
#<class 'list'> <class 'list'> this THIS 
#		 Note: Return keys() and values() as lists to allow indexing via a.keys()[0]

a.that='THAT'
#unlike attrDict, returns multiple values if asked
print(a('this', 'that'), "\n\t\t Note: a('this','that') returns a list")
print()

#new to attrThing:
#settable after the fact as in vPython
a(one=1,two=2,three=3)
print(a, '\n\t\t Note: Settable after the fact via a(one=1,two=2,three=3)')
print()
#		 Note: Return keys() and values() as lists to allow indexing via a.keys()[0]
#['THIS', 'THAT'] 
#		 Note: a('this','that') returns a list


a.l=[1,2,3]
a.t=(1,2,3)
print(a.l, 'should be list !!!') #note
#[1, 2, 3] should be list !!!

print(a.l, a('l'), a['l'], a.l ==a('l')==a['l'], 'all accessors return the same thing')
#[1, 2, 3] [1, 2, 3] [1, 2, 3] True all accessors return the same thing
a.l.append('this fails with the more sophisticated but mysterious https://pypi.python.org/pypi/attrdict')
print( a.l )

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants