Accessing Dict Keys Like an Attribute

How to use a dot . to access members of dictionary?

You can do it using this class I just made. With this class you can use the Map object like another dictionary(including json serialization) or with the dot notation. I hope to help you:

class Map(dict):
"""
Example:
m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
"""
def __init__(self, *args, **kwargs):
super(Map, self).__init__(*args, **kwargs)
for arg in args:
if isinstance(arg, dict):
for k, v in arg.iteritems():
self[k] = v

if kwargs:
for k, v in kwargs.iteritems():
self[k] = v

def __getattr__(self, attr):
return self.get(attr)

def __setattr__(self, key, value):
self.__setitem__(key, value)

def __setitem__(self, key, value):
super(Map, self).__setitem__(key, value)
self.__dict__.update({key: value})

def __delattr__(self, item):
self.__delitem__(item)

def __delitem__(self, key):
super(Map, self).__delitem__(key)
del self.__dict__[key]

Usage examples:

m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
# Add new key
m.new_key = 'Hello world!'
# Or
m['new_key'] = 'Hello world!'
print m.new_key
print m['new_key']
# Update values
m.new_key = 'Yay!'
# Or
m['new_key'] = 'Yay!'
# Delete key
del m.new_key
# Or
del m['new_key']

Accessing dictionary keys using dot(.)

By applying your example

class DotDict(dict):
pass

d = DotDict()
d.first_key = 1
d.second_key = 2
print(d.first_key)
print(d.second_key)

you set instance parameters first_key and second_key to your DotDict class but not to the dictionary itself. You can see this, if you just put your dictionary content to the screen:

In [5]: d
Out[5]: {}

So, it is just an empty dict. You may access dictionaries the common way:

In [1]: d={}

In [2]: d['first'] = 'foo'

In [3]: d['second'] = 'bar'

In [4]: d
Out[4]: {'first': 'foo', 'second': 'bar'}

Accessing object attributes using dictionary keys

You could use Python's built-in getattr function. The arguments to the getattr function should be the object and the string value of the attribute you want to get from the object. So in your case you could do getattr(regressor, h).

Accessing a dictionary as attributes of a custom class

For a more "IDE-friendly" option that provides type hinting and auto completion, I'd suggest looking into the Dataclass Wizard library for this. Just a disclaimer, that it's still in beta because I'm testing some things out, but it seems like it should work well enough for this use case.

Step 1: Generate a model for the data above

You can use an included CLI utility to do this as it's easier, but there's an easy way to do it programatically as well:

from dataclass_wizard.wizard_cli import PyCodeGenerator

string = """
{
"myapps": {
"app_1": {
"username": "admin",
"pwd": "S3cret",
"ports": [
8080,
443
],
"users": {
"user1": "john",
"user2": "ruth"
}
},
"app_2": {
"username": "user1",
"pwd": "P@ssword"
}
}
}
"""

print(PyCodeGenerator(file_contents=string).py_code)

Step 2: Load data into the model

from dataclasses import dataclass
from typing import List

from dataclass_wizard import JSONWizard

@dataclass
class Data(JSONWizard):
"""
Data dataclass

"""
myapps: 'Myapps'

@dataclass
class Myapps:
"""
Myapps dataclass

"""
app_1: 'App1'
app_2: 'App2'

@dataclass
class App1:
"""
App1 dataclass

"""
username: str
pwd: str
ports: List[int]
users: 'Users'

@dataclass
class Users:
"""
Users dataclass

"""
user1: str
user2: str

@dataclass
class App2:
"""
App2 dataclass

"""
username: str
pwd: str

data = Data.from_json(string)

repr(data)
# Data(myapps=Myapps(app_1=App1(username='admin', pwd='S3cret', ports=[8080, 443], users=Users(user1='john', user2='ruth')), app_2=App2(username='user1', pwd='P@ssword')))

Now you can use the dot . access, as intended. Type hinting for attributes should also work with your IDE (at least in Pycharm)

myapps = data.myapps

print("App_2 username = ", myapps.app_2.username) # prints App_2 username = user1
print("App_2 pwd = ", myapps.app_2.pwd) # prints App_2 pwd = P@ssword
print("App_1 ports = ", myapps.app_1.ports) # prints App_1 ports = [8080, 443]

myapps.app_2.username = "MyNewAdminAccount"
print("App_2 username = ", myapps.app_2.username) # prints App_2 username = MyNewAdminAccount

why can't I use '.' to access my dictionary

You cannot access object's items through dot-notation in Python. You're supposed to use braces.

screen.draw(game["img"]["bg"], (0,0)) 

Recursively access dict via attributes as well as index access?

Here's one way to create that kind of experience:

class DotDictify(dict):
MARKER = object()

def __init__(self, value=None):
if value is None:
pass
elif isinstance(value, dict):
for key in value:
self.__setitem__(key, value[key])
else:
raise TypeError('expected dict')

def __setitem__(self, key, value):
if isinstance(value, dict) and not isinstance(value, DotDictify):
value = DotDictify(value)
super(DotDictify, self).__setitem__(key, value)

def __getitem__(self, key):
found = self.get(key, DotDictify.MARKER)
if found is DotDictify.MARKER:
found = DotDictify()
super(DotDictify, self).__setitem__(key, found)
return found

__setattr__, __getattr__ = __setitem__, __getitem__

if __name__ == '__main__':

life = {'bigBang':
{'stars':
{'planets': {} # Value changed from []
}
}
}

life = DotDictify(life)
print(life.bigBang.stars.planets) # -> []
life.bigBang.stars.planets.earth = {'singleCellLife' : {}}
print(life.bigBang.stars.planets) # -> {'earth': {'singleCellLife': {}}}

Set attributes from dictionary in python

Sure, something like this:

class Employee(object):
def __init__(self, initial_data):
for key in initial_data:
setattr(self, key, initial_data[key])

Update

As Brent Nash suggests, you can make this more flexible by allowing keyword arguments as well:

class Employee(object):
def __init__(self, *initial_data, **kwargs):
for dictionary in initial_data:
for key in dictionary:
setattr(self, key, dictionary[key])
for key in kwargs:
setattr(self, key, kwargs[key])

Then you can call it like this:

e = Employee({"name": "abc", "age": 32})

or like this:

e = Employee(name="abc", age=32)

or even like this:

employee_template = {"role": "minion"}
e = Employee(employee_template, name="abc", age=32)


Related Topics



Leave a reply



Submit