1

I am having a use case where I want to store a key value pair in dictionary. The problem I'm facing is my key is 'copy'. So after inserting 'copy' key, I'm not able to access it via getattr method, since it always returns the copy method of dict.

I cannot use get method on dict because my code is unaware of the type of object that is being passed. So, I went ahead with using getattr which is generic function to access properties.

I also created a custom class inheriting from dict and wrote getattribute but that blocks access to methods


class DictLike(dict):
    def __getattribute__(self, k):
        try:
            return self[k]
        except KeyError:
            getattr(super(DictLike, self), k)

    def paste(self):
        return "Test"



a = DictLike()
a['copy'] = 1;
a['state'] = 'completed'

print(getattr(a, 'copy')) // prints 1
print(a.paste()) // this does not works

b = {'copy': 1}

print(b.get('copy')) \\ 1
getattr(b, 'copy') \\ function


Is there a way I could fix this behavior ?

Deepanshu Arora
  • 375
  • 1
  • 5
  • 21
  • 1
    Why on earth would you use `getattr()` on a `dict` to retrieve the value associated with a key ??? `getattr()` is for __attributes__ access, not for subscripting. `getattr()` will NEVER return the value for a key of a dict. – bruno desthuilliers Jun 26 '19 at 10:20
  • "I cannot use get method on dict because my code is unaware of the type of object that is being passed." => please explain what this is supposed to mean. – bruno desthuilliers Jun 26 '19 at 10:25
  • "So, I went ahead with using getattr which is generic function to access properties" => dict keys are NOT properties. – bruno desthuilliers Jun 26 '19 at 10:26
  • 1
    typical XY problem (https://en.wikipedia.org/wiki/XY_problem). Please explain your __real__ problem (=> " cannot use get method on dict because my code is unaware of the type of object that is being passed.") instead. – bruno desthuilliers Jun 26 '19 at 10:30
  • are you aware that you can just do `print(a['copy'])` to print the value of the item corresponding to the 'copy' key ? –  Jun 26 '19 at 10:31
  • @brunodesthuilliers I am trying to read a file which has a column 'copy'. DictLike object is one container in a strategy to read this file.There are other strategies also which read other files into other custom objects. – Deepanshu Arora Jun 26 '19 at 10:40

4 Answers4

3

Here is the working solution:

class DictLike(dict):

    def __init__(self, *args, **kw):
        super(DictLike, self).__init__(*args, **kw)
        self.itemlist = super(DictLike, self).keys()

    def __getattribute__(self, k):
        try:
            return self[k]
        except Exception as e:
            return super().__getattribute__ (k)

    def paste(self):
        return "Test"


a = DictLike()
a['copy'] = 1
a['state'] = 'completed'

print(getattr(a, 'copy'))
print(a.paste())
Ashutosh gupta
  • 447
  • 4
  • 16
0

It seems to work if you define __getattr__ instead of __getattribute__.

jacalvo
  • 656
  • 5
  • 14
  • Re-read the question more carefully. The root problem is that the OP seems to be thinking that `getattr(d, somekey)` works the same as `d[somekey]`. – bruno desthuilliers Jun 26 '19 at 10:22
  • I understood that the problem was the call to `a.paste()` not working, using `__getattr__` fixes that. – jacalvo Jun 26 '19 at 10:26
  • 1
    As I said, re-read the WHOLE post. This is typically a XY problem (cf the "I cannot use get method on dict because my code is unaware of the type of object that is being passed. So, I went ahead with using getattr" part). – bruno desthuilliers Jun 26 '19 at 10:28
0

You're right you wont be able to use getattr to get the key named "copy". As I feel like you might know, Python PEP standards suggest changing the name for keywords if there is conflicting namespaces. However, yours isn't a keyword, I'd still follow this standard. Current standard is trailing underscore such as "copy_". Stated here in PEP8 standards: "single_trailing_underscore_: used by convention to avoid conflicts with Python keyword."

I'm confused what you mean by dictVar.get() can't access your key because its unaware of the type. What other type are you passing. it works for strings or ints for certain.

Tyler Estes
  • 59
  • 1
  • 5
  • `getattr` will not get the key named "copy_" either (on a dict I mean). – bruno desthuilliers Jun 26 '19 at 10:25
  • Yessir, I understand that. I didn't suggest that to him. I said he would not be able to access the key "copy" with `getattr`. I suggest he rename his key to "copy_". This can therefore accessed by `myDict.get("copy_")` with no confusion (even though `myDict.get("copy")` also works). EDIT: I see where my wording could have been poor. But, for the record I am not suggesting to use getattr to get a key's value. – Tyler Estes Jun 26 '19 at 10:31
-1

You should use getattr, here's a good explanation - Difference between __getattr__ vs __getattribute__

So, it works perfectly:

class DictLike(dict):                                                                                                      
    def __getattr__(self, k):                                                                                              
        try:                                                                                                               
            return self[k]                                                                                                 
        except KeyError:                                                                                                   
            getattr(super(DictLike, self), k)                                                                              

    def paste(self):                                                                                                       
        return "Test"                                                                                                      


a = DictLike()                                                                                                             
a['copy'] = 1;                                                                                                             
a['state'] = 'completed'                                                                                                   

print(a['copy'])                                                                                                           
print(a.paste())  

And the output is:

1
Test
Sergius
  • 908
  • 8
  • 20
  • 2
    Re-read the question more carefully. The root problem is that the OP seems to be thinking that `getattr(d, somekey)` works the same as `d[somekey]`. – bruno desthuilliers Jun 26 '19 at 10:22