-1

I would like to understand the difference between these two syntaxes:

Ex:.

obj = { 
'atrib1': 1,
'atrib2': 2
}

#accessing atrib1
print(obj['atrib1'])

#why can't I access like this, and what is accessible in this way?
#print(obj.atrib1)
khelwood
  • 55,782
  • 14
  • 81
  • 108
  • 2
    These two syntaxes are nothing alike. I'm not sure why you would have an expectation that they would produce the same results (besides the fact that in Lua or maybe JavaScript, they would). – Nicol Bolas Jun 23 '19 at 21:01
  • Hello and welcome to SO. This question is a possible duplicate of [this](https://stackoverflow.com/questions/4984647/accessing-dict-keys-like-an-attribute) – Sıddık Açıl Jun 23 '19 at 21:01
  • 1
    Possible duplicate of [Accessing dict keys like an attribute?](https://stackoverflow.com/questions/4984647/accessing-dict-keys-like-an-attribute) – khelwood Jun 23 '19 at 21:06
  • 1
    @khelwood: "How to do it" is not the same question as "why you can't do it". – Nicol Bolas Jun 23 '19 at 21:08
  • There's information in the other questions' answers about why they are different operations. – khelwood Jun 23 '19 at 21:10
  • 2
    And what makes you think either of these syntaxes involves anything called "fields"? – Daniel Roseman Jun 23 '19 at 21:16

2 Answers2

2

In languages like Lua and JavaScript, where what you can access via obj.attr and obj["attr"] is the same, you'll notice that the APIs for manipulating a dictionary are not actually part of the dictionary object. For example, if you want to get the keys of a dictionary as a list, in JavaScript, you call Objects.keys(), passing the dictionary as a parameter. You don't call the_dictionary.keys().

The reason these are external functions rather than member functions is that the keys in the key/value dictionary could override member functions. If a dictionary just so happened to have a key named "keys", any member function named "keys" would be overridden. Therefore, functions which act on dictionaries cannot be members of the actual dictionary type.

In Python, they can be. The contents of a dictionary are accessed via [], but the member functions, the operations which act upon those contents, are accessed via .name notation. That's the distinction between attributes and "fields". And that means the operations on dictionaries are actually on the dictionary.

You can of course make them one and the same, but then you recreate the original problem. And since Python doesn't have that problem normally, it doesn't have non-member functions you can easily call to do that job. You can still do it via the class object, but it's clearly non-Pythonic.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
1

In Python, objects have attributes, which may be accessed with the .name syntax. But some object classes implement a __getitem__ method, which is accessed with the ['name'] syntax. Most notably, the dict class:

In [102]: obj = {  
     ...: 'atrib1': 1, 
     ...: 'atrib2': 2 
     ...: } 
     ...:                                                                                            
In [103]: type(obj)                                                                                  
Out[103]: dict

obj['atrib1'] is translated by the interpreter into a method call:

In [104]: obj.__getitem__('atrib1')                                                                   
Out[104]: 1

obj.atrib1 is translated into an __getattribute__ call:

In [105]: obj.__getattribute__('atrib1')                                                             
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-105-ec1bc68ae22d> in <module>
----> 1 obj.__getattribute__('atrib1')

AttributeError: 'dict' object has no attribute 'atrib1'

That class does have attributes like __getattribute__ and keys, which are functions:

In [106]: obj.__getattribute__('__getitem__')                                                        
Out[106]: <function dict.__getitem__>
In [107]: obj.__getattribute__('keys')                                                               
Out[107]: <function dict.keys>

So the dict object does have a lot of attributes, but the items access with keys aren't attributes.

Some classes also implement a __dict__ attribute, which stores user defined attributes. vars(obj) returns that as dict. But for this dict class:

In [108]: vars(obj)                                                                                  
...
TypeError: vars() argument must have __dict__ attribute

Here's a little class that has both:

In [111]: class mydict(dict): 
     ...:     pass 
     ...:                                                                                            
In [112]: obj1 = mydict()                                                                            
In [113]: obj1 = mydict(atrib1=1, atrib2=2)                                                          
In [114]: obj1                                                                                       
Out[114]: {'atrib1': 1, 'atrib2': 2}
In [115]: obj1.__dict__                                                                              
Out[115]: {}
In [116]: obj1.foobar = 42                                                                           
In [117]: vars(obj1)                                                                                 
Out[117]: {'foobar': 42}
In [118]: obj1.foobar                                                                                
Out[118]: 42
In [119]: obj1['atrib1']                                                                             
Out[119]: 1
hpaulj
  • 221,503
  • 14
  • 230
  • 353