Get name of dictionary
Asked Answered
A

7

16

I find myself needing to iterate over a list made of dictionaries and I need, for every iteration, the name of which dictionary I'm iterating on.

Here's an MRE (Minimal Reproducible Example).
Contents of the dicts are irrelevant:

dict1 = {...}
dicta = {...}
dict666 = {...}

dict_list = [dict1, dicta, dict666]

for dc in dict_list:
    # Insert command that should replace ???
    print 'The name of the dictionary is: ', ???

If I just use dc where ??? is, it will print the entire contents of the dictionary. How can I get the name of the dictionary being used?

Arse answered 5/8, 2014 at 18:58 Comment(2)
Dictionaries do not inherently have names. Variables, as a general rule, do not inherently have names. If you're trying to get the name of the variable you assigned it to, I don't think that can be done, since you could have multiple variables pointing to the same dictionary.Samathasamau
#2553854Undersexed
F
22

Don't use a dict_list, use a dict_dict if you need their names. In reality, though, you should really NOT be doing this. Don't embed meaningful information in variable names. It's tough to get.

dict_dict = {'dict1':dict1, 'dicta':dicta, 'dict666':dict666}

for name,dict_ in dict_dict.items():
    print 'the name of the dictionary is ', name
    print 'the dictionary looks like ', dict_

Alternatively make a dict_set and iterate over locals() but this is uglier than sin.

dict_set = {dict1,dicta,dict666}

for name,value in locals().items():
    if value in dict_set:
        print 'the name of the dictionary is ', name
        print 'the dictionary looks like ', value

Again: uglier than sin, but it DOES work.

Figurehead answered 5/8, 2014 at 19:1 Comment(11)
Don't embed meaningful information in variable names, but variable names are meaningful information.Arse
@Arse if the name is meaningful, it should be in a dict where you can access it. Otherwise treat it as a throwaway that's easier to remember than a memory location (it's really just a pointer to 0xFAC4928FD9 anyway)Figurehead
@Arse any information that's actually meaningful to your program should be stored in variable data, not a variable name.Samathasamau
A better way of phrasing it would be "don't embed information that is meaningful to the program in variable names", as it is hard to retrieve and easily broken by code changes.Sofar
@Gabriel: Also see Keep data out of your variable names for some good reasons not to do it.Lyrebird
Thanks everybody, I'll keep this information in mind.Arse
@Arse don't feel too admonished. Everybody did it at some point which is why it's now so strongly suggested NOT to do that. I myself wrote a script about a year ago that had to go gather some filesize information for about 12 files each off ~100 machines to find out which machines weren't purging their history files. I designed it as FILENAME = [('machine_name', size), ...] for each file, and it was the biggest hackiest piece of crap script I'd ever written. I can't even use it anymore because I don't know how to maintain it anymore -- had to re-write from scratch a month ago.Figurehead
The OP's question is legitimate for automation. For example, DNA sequencing. Let's say I have 1000 samples, and for each sample, I want to compare the sample sequence with a user-specified list of input reference sequences. Instead of building a dictionary sample by sample, I can build a dictionary once for each input reference region, then for each sample, pull out the appropriate reference dictionary by name from a list of dictionaries, and compare between reference dictionary and sample. So instead of computing 1000's of dictionaries, I compute a limited list of them, just once.Tyler
@Tyler isn't that what functools.lru_cache is for?Figurehead
@AdamSmith I haven't seen it used in this context; but would love to see an example!Tyler
@Tyler hmm maybe I misunderstood. I thought your concern was that you had an expensive function call that you didn't want to repeat over many many possible identical data points (which is where lru_cache shines). I guess I don't really understand your use case, and why a list of dictionaries where you have to divine the name bound to each one is superior to a dictionary of dictionaries keyed by their name?Figurehead
U
4

You should also consider adding a "name" key to each dictionary.

The names would be:

for dc in dict_list:
    # Insert command that should replace ???
    print 'The name of the dictionary is: ', dc['name']
Uncertain answered 5/8, 2014 at 19:2 Comment(0)
L
3

Objects don't have names in Python, a name is an identifier that can be assigned to an object, and multiple names could be assigned to the same one.

However, an object-oriented way to do what you want would be to subclass the built-in dict dictionary class and add a name property to it. Instances of it would behave exactly like normal dictionaries and could be used virtually anywhere a normal one could be.

class NamedDict(dict):
    def __init__(self, *args, **kwargs):
        try:
            self._name = kwargs.pop('name')
        except KeyError:
            raise KeyError('a "name" keyword argument must be supplied')
        super(NamedDict, self).__init__(*args, **kwargs)

    @classmethod
    def fromkeys(cls, name, seq, value=None):
        return cls(dict.fromkeys(seq, value), name=name)

    @property
    def name(self):
        return self._name

dict_list = [NamedDict.fromkeys('dict1', range(1,4)),
             NamedDict.fromkeys('dicta', range(1,4), 'a'),
             NamedDict.fromkeys('dict666', range(1,4), 666)]

for dc in dict_list:
    print 'the name of the dictionary is ', dc.name
    print 'the dictionary looks like ', dc

Output:

the name of the dictionary is  dict1
the dictionary looks like  {1: None, 2: None, 3: None}
the name of the dictionary is  dicta
the dictionary looks like  {1: 'a', 2: 'a', 3: 'a'}
the name of the dictionary is  dict666
the dictionary looks like  {1: 666, 2: 666, 3: 666}
Lyrebird answered 5/8, 2014 at 20:0 Comment(1)
Inspired! I love it :DFigurehead
W
2

If you want to read name and value

dictionary={"name1":"value1","name2":"value2","name3":"value3","name4":"value4"}
for name,value in dictionary.items():
    print(name)
    print(value)

If you want to read name only

dictionary={"name1":"value1","name2":"value2","name3":"value3","name4":"value4"}
for name in dictionary:
    print(name)

If you want to read value only

dictionary={"name1":"value1","name2":"value2","name3":"value3","name4":"value4"}
for values in dictionary.values():
    print(values)

Here is your answer

dic1 = {"dic":1}
dic2 = {"dic":2}
dic3 = {"dic":3}
dictionaries = [dic1,dic2,dic3]
for i in range(len(dictionaries)):
  my_var_name = [ k for k,v in locals().items() if v == dictionaries[i]][0]
  print(my_var_name)
Woodson answered 5/2, 2020 at 10:47 Comment(2)
You misunderstood the question Habibur. I meant the name of the dictionary itself, not the keys and params inside.Arse
Gabriel I have updated my answer please check. Thank youWoodson
T
0

The following doesn't work on standard dictionaries, but does work just fine with collections dictionaries and counters:

from collections import Counter

# instantiate Counter ditionary
test= Counter()

# create an empty name attribute field
test.name = lambda: None

# set the "name" attribute field to "name" = "test"
setattr(test.name, 'name', 'test')

# access the nested name field
print(test.name.name)

It's not the prettiest solution, but it is easy to implement and access.

Tyler answered 22/3, 2019 at 19:58 Comment(0)
B
0

Here's my solution for a descriptive error message.

def dict_key_needed(dictionary,key,msg='dictionary'):
    try:
        value = dictionary[key]
        return value
    except KeyError:
         raise KeyError(f"{msg} is missing key '{key}'")
Baldpate answered 17/1, 2020 at 16:52 Comment(0)
H
0

Just like list in R, Record in OCaml or object in JS, in Python, dict is just a value, not a key-value, and the elements in it are key-value, that means both of those elements have name (because the dict they live in will record their names) and don't means this dict it self have a name.

So, if you need to record names about some dicts or what ever anything, you shouldn't use [] to package them, you should use {} and within names you want to specify:

dict1 = {... something in dict1 ...}
dicta = {... something in dicta ...}
...

dicts_dc = {'dict1': dict1, 'dicta': dicta, ...}

# means: 
# 
# dicts_dc = {
#   'dict1': {... something in dict1 ...}, 
#   'dicta': {... something in dicta ...}, 
#   ... }
# 

Or, you can also package them by [], but you should record your dicts' names inside every dict object, such as:

dict1 = {'name': 'dict1', ...}
dicta = {'name': 'dicta', ...}
...

dicts_ls = [dict1, dicta, ...]

# means: 
# 
# dicts_ls = [
#   {'name': 'dict1', ...}, 
#   {'name': 'dicta', ...}, 
#   ...]
# 

Then, for the way one, you can get their names or values by these:

# get names use: 
[n for n in dicts_dc] # or: 
[* dicts_dc] # or: 
list (dicts_dc) # or: 
[n for n,x in dicts_dc.items()]

# get values use: 
[x for x in dicts_dc.values()] # or: 
[* dicts_dc.values()] # or: 
list (dicts_dc.values()) # or: 
[x for n,x in dicts_dc.items()]

And for the way two, you can get their names by:

[x['name'] for x in dicts_ls]

You can see a live demo here.

Halt answered 22/2 at 9:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.