1

So I am trying to pull information from a dictionary list that I made in a specific format but for the life of me I cannot create a loop that pulls the information from exactly where I need it at all, it prints nothing but I receive no errors. Here's an example:

class Global():
    prv_word = 'dumb'
    cur_word = 'dog'
    nxt_word = 'head'

class Animal():
    dog = [
    {'head': {'funny': [8 , 7 , 1],'dumb': [9 , 3 , 2],'poofy': [18 , 4 , 11]}},
    {'tail': {'funny': [12, 2 , 4], 'dumb': [3 , 9 , 7],'poofy':[28 , 5 , 60]}}]

dog_cur = f'Animal.{Global.cur_word}'

if hasattr(Animal, Global.cur_word):
    for list in dog_cur:
        if Global.nxt_word in list:
            adj = Global.nxt_word
            index = list.index(Global.nxt_word)
            for lis in list:
                if Global.prv_word in lis:
                    adj2 = Global.prv_word
                    index2 = lis.index(Global.prv)
                    end = dog_cur[index][adj][adj2]
                    print(end)

##### TROUBLESHOOT #####
##### This works! But how do I format the loop to generate this result? #####
(print(Animal.dog[0]['head']['dumb']))

can someone help show me a way to make this loop pop up with a relevant value of [9, 3, 2]. I also don't think the formatted dog_cur variable will work... Is there another way to format that variable to equal the same result as f'Animal.{Global.cur_word}' I believe if you look at my loop, you'll be able to see I'm trying to pull the values from a list within a dictionary. In my actual program, the Global values are constantly changing so that's why I need a loop that can find those values. Help will be greatly appreciated! Thank you

Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
Zoetyc
  • 67
  • 6
  • I changed: `if hasattr(Animal, Global.cur_word): for list in dog_cur: if Global.nxt_word in list: adj = Global.nxt_word` to `if hasattr(Animal, Global.cur_word): if Global.nxt_word in Animal.dog: adj = Global.nxt_word index = list.index(Global.nxt_word)` and it returns as `'dict' object has no attribute 'index'` but now I need to find a loop for dict and the lists within – Zoetyc Oct 06 '18 at 07:36
  • I don't understand why you need a loop at all. You'll have to do a better job describing what your code is supposed to do than just "I'm trying to pull information from a dictionary list". – Aran-Fey Oct 06 '18 at 07:53
  • Problem is also b/c of this statement `dog_cur = f'Animal.{Global.cur_word}'`. On the output you receive not list type from `Animal` class, but string type 'Animal.dog'. And of course, this string does not contain "head" string what is searched in the loop... – kosist Oct 06 '18 at 08:10
  • You are using classes where you really want to scope variables and it is "going against the grain" if you will of python. – SargeATM Oct 06 '18 at 08:28
  • @SargeATM Do you think I should maybe create a seperate .py file with just variables? and import that and call on it? I was going to probably go this route but I just didn't understand why I was having an issue with a loop. I was so stuck on it, all of your answers are very clean ways of resolving my issue. – Zoetyc Oct 06 '18 at 09:38
  • @Zoetyc, are you trying to use .py files to feed data to your program? – SargeATM Oct 06 '18 at 09:42
  • @SargeATM Well, I'm relatively new to python. I've been working on my knowledge, so for the time being I was going to use .py but I am definitely curious if there are more efficient methods of pulling information via .db or something similar where I can use a very similar format to the dictionary I showed in this brief example program here. Any suggestions? – Zoetyc Oct 06 '18 at 10:00
  • very common formats to use are json and yaml files. Python has excellent libraries for both. – SargeATM Oct 06 '18 at 10:03
  • Ok thanks! I appreciate your help man – Zoetyc Oct 06 '18 at 10:08

3 Answers3

0

Why not put that in dicts all the way?

class Animals():
    animals = { 
        "dog" : {
            'head': {'funny': [8 , 7 , 1], 'dumb': [9 , 3 , 2], 'poofy': [18 , 4 , 11]},
            'tail': {'funny': [12, 2 , 4], 'dumb': [3 , 9 , 7], 'poofy': [28 , 5 , 60]}},
        "cat" : { "head": {"mysterious": [1,1,1] }}}

    @classmethod
    def gett(cls, name, part_name = None, style_name = None):
        """Provide getter on inner dict. Returns None if any key given
        is invalid. Allows to specify keys partly, to get more infos on
        inner dict"""
        if name is None:
            raise ValueError("name can not be None")

        try:
            if part_name and style_name :
                return cls.animals.get(name).get(part_name).get(style_name)
            elif part_name:
                return cls.animals.get(name).get(part_name)
            else:
                return cls.animals.get(name)
        except:
            return None

print(Animals.gett("dog","head","dumb")) 
print(Animals.gett("cat","head","mysterious"))
print(Animals.gett("donkey","whatever","yeah"))
print(Animals.gett("dog"))

Output:

[9, 3, 2]
[1, 1, 1]
None
{'head': {'funny':  [8, 7, 1], 'dumb': [9, 3, 2], 'poofy': [18, 4, 11]}, 
 'tail': {'funny': [12, 2, 4], 'dumb': [3, 9, 7], 'poofy': [28, 5, 60]}}

I dont know if you want to put more effort in it, if so you could mimic a dict: see How to "perfectly" override a dict?

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
  • I quite like this answer as you have expanded the dictionary a bit and allowed me if statements so that I can possibly return values with just a few words as opposed to relying on having the full scope of words. Could I change it and make `"dog" : { 'head': 18 , {'funny': [8 , 7 , 1], 'dumb': [9 , 3 , 2], 'poofy': [18 , 4 , 11]}` and call on `'head': 18` value using this as well? or maybe even `'head' : [1, 2 ,3]` – Zoetyc Oct 06 '18 at 09:51
  • @Zoetyc `"dog" : { 'head': 18 , {'funny': [8 , 7 , 1], 'dumb': [9 , 3 , 2], 'poofy': [18 , 4 , 11]}` is no valid data structure - the `{'funny': [8 , 7 , 1], 'dumb': [9 , 3 , 2], 'poofy': [18 , 4 , 11]}` part misses its key - so it wont run. – Patrick Artner Oct 06 '18 at 09:58
  • I figured it wouldn't function, could I do something like: `dog" : { 'head': [1 , 2 , 3], default: {'funny': [8 , 7 , 1], 'dumb': [9 , 3 , 2], 'poofy': [18 , 4 , 11]}` would that work? – Zoetyc Oct 06 '18 at 10:06
  • @Zoetyc if you'd `c = Animals.gett("dog","whisker") or Anumals.gettt("dog","default")` - if would give you the default as the `whisker` is not specified. If you plan a "general default" I would handle that inside `gett` - instead of returning a None, check for "default" given, and return that ifsomethings requested that does not exist. Play with the code, have fun. – Patrick Artner Oct 06 '18 at 10:14
0
class Global():
    prv_word = 'dumb'
    cur_word = 'dog'
    nxt_word = 'head'

class Animal():
    dog = [
    {'head': {'funny': [8 , 7 , 1],'dumb': [9 , 3 , 2],'poofy': [18 , 4 , 11]}},
    {'tail': {'funny': [12, 2 , 4], 'dumb': [3 , 9 , 7],'poofy':[28 , 5 , 60]}}]

def find():
    animal_list = getattr(Animal,Global.cur_word, None)
    if animal_list is None: return None 

    animal_part = next(filter(lambda pdct: Global.nxt_word in pdct, animal_list), None)
    if animal_part is None: return None 

    if Global.nxt_word in animal_part and Global.prv_word in animal_part[Global.nxt_word]:
        animal_part_data = animal_part[Global.nxt_word][Global.prv_word]
        return animal_part_data
    else:
        return None

print(find())
SargeATM
  • 2,483
  • 14
  • 24
  • This is probably the most straight forward method of trying to resolve my issue. My one concern is I have to check to see if I can run each part of the code, should I just do: `def find(): try: animal_list = getattr(Animal,Global.cur_word) animal_part = next(filter(lambda pdct: Global.nxt_word in pdct, animal_list)) animal_part_data = animal_part[Global.nxt_word][Global.prv_word] return animal_part_data except: None` or should I throw if statements in there? What is your opinion? – Zoetyc Oct 06 '18 at 09:41
  • I like to use if statements. It prevents masking exceptions that you weren't expecting. It makes debugging and logging easier. I updated the example to include error checking. – SargeATM Oct 06 '18 at 09:51
0

I had to add another answer that used classes in an object-oriented fashion. This is the way I would go about setting up the structure of your solution.

class Selector(object):
    def __init__(self, animal="", part="", descriptor=""):
        super(Selector, self).__init__()
        self.animal = animal
        self.part = part
        self.descriptor = descriptor

current_selector = Selector("dog", "head", "dumb")

class Animal(object):
    def __init__(self, kind="", parts=[]):
        super(Animal, self).__init__()
        self.kind = kind
        self.parts = parts

    def find_part(self, part_name):
        return next(filter(lambda p: p.name == part_name, self.parts), None)

class AnimalPart(object):
    def __init__(self, name="", descriptors={}):
        super(AnimalPart, self).__init__()
        self.name = name
        self.descriptors = descriptors

    def find_descriptor(self, desc_name):
        return self.descriptors[desc_name]


animals = {}

def init():
    # create dog
    dog = Animal("dog", [   AnimalPart('head', {'funny': [8 , 7 , 1],'dumb': [9 , 3 , 2],'poofy': [18 , 4 , 11]}),
                            AnimalPart('tail', {'funny': [12, 2 , 4], 'dumb': [3 , 9 , 7],'poofy':[28 , 5 , 60]})])
    animals['dog'] = dog

def find():
    sel = current_selector
    return animals[sel.animal].find_part(sel.part).find_descriptor(sel.descriptor)

init()
print(find())
SargeATM
  • 2,483
  • 14
  • 24