Python dictionary help

I want to use a machine name the product code to look up the run rate.

Some machines make the same products at different speeds.

When I look up dictionaries on W3schools though and other python dictionary references, I only see key:value. Or in other cases, the content jumps way over my head, and I don’t know how to read what I see.

How do I make more complex dictionaries, and how do I access items in them?

I wouldn’t be using a dictionary, I’d be using a sql table/s to store that info, or a dataset tag. These will be globally accessible, easier to use and maintain, and usable within things like dropdown menus

1 Like

Thanks, I had forgotten why I didn’t learn about more complex dictionaries.

I did it the query way in previous scripts. Thanks

Line       = self.parent.parent.getChild("Flex1").getChild("Dropdown_Line").props.value
Production= self.parent.parent.getChild("Flex2").getChild("Dropdown_Product").props.value
 
result = system.db.runScalarPrepQuery("SELECT rate FROM myTable WHERE Line = ? and product =? ", [Line,Product])

event.source.parent.getComponent("Text Field").data = result

This syntax is correct for the “?” and two variables?

I will test in the script console.

I am not sure my script will run faster. I also need to update my try-except label changing for when the product and machine combo needs a rate.

You have a Production variable and are trying to use a Product variable

1 Like

Don’t let it stop you from learning about them though. Dictionaries can be a useful tool, used judiciously.

Example you can play with. Each nested dictionary gets it’s key in it’s own bracket.

lineDict = {'Machine1' : {'ProductABC' : {'rate' : 120, 'boxQty' : 100},
						  'ProductDEF' : {'rate' : 100, 'boxQty' : 150}
						 },
			'Machine2' : {'ProductLMN' : {'rate' : 90,  'boxQty' : 200},
						  'ProductOPQ' : {'rate' : 130, 'boxQty' : 180}
						 },
			'Machine3' : {'ProductUVW' : {'rate' : 160, 'boxQty' :  80},
						  'ProductXYZ' : {'rate' : 165, 'boxQty' : 240}
						 }
		   }

print lineDict['Machine1']['ProductDEF']['rate']

4 Likes

Nested dictionaries are very useful and the first step to more complex dictionaries.

Next step I think is realizing that you can use a dictionary as a makeshift switch statement. Imagine the following on a vision client startup script

STARTUP_FUNC_MAPPING = {
    "brian":user.brianStartUp
    "eric":user.adminStartUp
    "john":user.salesStartUp
}

username = system.security.getUsername()

try:
    # will call the right function if brian/eric/john login
    STARTUP_FUNC_MAPPING[username]()
except KeyError, e:
    # calls this function if anyone else logs in
    user.normalStartUp()

Ultimately the dictionary is just a mapping technique where you can map two arbitrary objects together. Recently I had a situation where I had to be able to save a bunch of plc tags to a database table where each plc had its own column, and at another point, be able to retrieve them from the columns and write them to the plc tags. I used a dictionary like

PLC_TO_DB_MAPPING = {
"some/plc/tag/address":"someDBColumn",
"another/plc/tag/address":"anotherDBColumn",
...
}

This allowed me to write two generic functions, one to read from the plc and write to the db, and another that did the opposite.

Now combining this idea mapping two arbitrary objects with what @JordanCClark has shown about how you can nest dictionaries arbitrarily deep and you can now make your configurations different. Save for instance I only wanted to save some of the PLC tags when writing but not all of them, because when reading them back sometimes I want to give them a constant instead. I could do something like

PLC_TO_DB_MAPPING = {
"some/plc/tag/address":{"saveToDb":True, "dbColumn":"someDBColumn"},
"another/plc/tag/address":{"saveToDb":False, "constantValue":5},
...
}

The last “advanced” or complex usage I do or have seen with dictionaries is basically trying to create an ORM with them that maps to a database table or row directly. Say you have a db table

id       name                number            value_1      value_2
1        'bob'                 45               1.234        3.145

And that you need to use a record from this table in your code somethwere, it becomes much more legible as you will be able to reference the table names directly

recordData = mySpecialDbLibrary.getRecord("someTable",id=1)
if recordData['name'] == 'bob':
    # do something

That’s all I got to say about dictionaries and the advanced/complex way to use in relation ignition. I hope this is relevant to your topic as you said you wanted to know more about complex dictionaries. I’m sure there are a few other use cases others can have but these are the big ones I’ve seen/used personally.

1 Like

I bookmarked this thread.

Thanks for the help guys.

Why not use get() and pass it a default value instead ?

STARTUP_FUNC_MAPPING.get(username, user.normalStartUp)()

I really tend to avoid try/except if I can. It reduces nesting and clutter.

4 Likes

That is because I never heard of .get() on a dictionary before! So the second argument is the fall back in the event of the keyerror right? This is nice and more succinct, thanks for the tip.

For explanatory purposes I think they try/except is good to explain what is going on. Agree that .get() seems to be cleaner in general though.

1 Like

Can it work with multiple keys?

I am not sure how to ask the question. I mean like in Jordan’s examples, the dictionary has more than just 1:1.

Yes, the second argument is a fall back value.

@zacharyw.larson I have no idea what you’re asking

edit: oh wait I think I get it. Here’s where you’re confused: they ARE just 1:1. It’s always key: value. Except the value can be a dictionary, which then has its own key: value pairs.

1 Like

Yes, assuming the first value is a dictionary you can do this:

dict1.get('someKey',doFirstFallback).get('someOtherKey',doSecondFallback)

Note that if the first Key is not found then it will return doFirstFallback and if the second Key isn’t found then it will return doSecondFallback

As @pascal.fragnoud points out the first fallback needs to a dictionary (or at least have a get attribute) though that could lead to bugs if you’re not careful.

dict1.get('someKey',{}).get('someOtherKey',fallback)

A dictionary by definition is just a collection of Key:Value pairs. The Key can be any value of an immutable type. Keys can not be duplicated. The Value can be a value of any type.

Some more on https://towardsdatascience.com/https-towardsdatascience-com-python-basics-mutable-vs-immutable-objects-829a0cb1530a

1 Like

In this case, the first fallback needs to be a dictionary (or return one), otherwise the second .get will throw an error.

3 Likes