# Python List Comprehensions Help

**URL:** <https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621>\
**Category:** Ignition\
**Created:** [February 28, 2022, 3:12pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621 "2022-02-28T15:12:54Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 1, 2022, 1:45pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/21 "2022-03-01T13:45:40Z")

</div>

That is a specific version, is there a particular reason?

I do have a running list of different priorities among the updates, but that one was not on my radar specifically  
My top two reasons or motivations were for these  
8.1.6 fixes sorting and now I know it adds the scheduling to the gateway scripts  
8.1.11 and 8.1.12 fix bindings on multiple views

I am not sure what the deciding factors are, but I agree that updating will help.

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [March 1, 2022, 2:00pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/22 "2022-03-01T14:00:20Z")

</div>

Its just the latest stable version, unless a regression is found I like staying up to date as much as possible.

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [March 1, 2022, 2:14pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/23 "2022-03-01T14:14:10Z")

</div>

> [@zacharyw.larson](#):
>
> I do have a running list of different priorities among the updates, but that one was not on my radar specifically

Once a stable version is released, and it's just a minor version upgrade there really isn't much risk in just upgrading. Especially if you have a development server set up.

Why not work with the latest and greatest tools if you can? 8.1.0 is coming up on 2 years old at this point.

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 1, 2022, 2:17pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/24 "2022-03-01T14:17:06Z")

</div>

I am used to using a “preferred” version of software and then just never ever changing.  
I am the type of consumer the new XP operating system laptops are meant for haha.

The real initial pain point, that causes me to want to pick a preferred version, was trying to play table top games online with java based applications that everyone could run. In this case I want to update.

I think many drive thru banks and ATMs still use XP.

@lrose  
It isn’t my choice on the updating. I would choose to update in this case. The larger the group using something, the less agility it has I think.

I am not sure if I worded it the best. I mean for the best.

I think when I used IQAN, I liked version 3.4  
With RS Logix, they have a version they call the golden version

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [March 1, 2022, 2:42pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/25 "2022-03-01T14:42:55Z")

</div>

> [@zacharyw.larson](#):
>
> It isn’t my choice on the updating. I would choose to update in this case. The larger the group using something, the less agility it has I think.

I understand that you may be restrained on upgrading, but this is like not upgrading from Windows XP to Windows XP Service Pack 3. (To use you're own example)

I have similar feelings when it comes to not upgrading Firmware versions for RSLogix. There is a reason the company released that minor change. Perhaps it doesn't effect you (yet), but it may. Also, I've dealt with the calls into any tech support for software, where question No. 1 is have you installed the latest patch?

There is definitely less freedom in the upgrade process with a larger group, but this is an extremely new platform in the world of software development and updates, and by extension upgrades, should be expected to be more common.

Any way, were moving away from the topic of this thread so, I'll just leave it there.

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 1, 2022, 2:50pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/26 "2022-03-01T14:50:26Z")

</div>

that is funny, I don’t upgrade to service pack 3 on XP because the plcs I connect won’t work with it

but agreed, off topic

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 10, 2022, 2:32pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/27 "2022-03-10T14:32:45Z")

</div>

> [@Python List Comprehensions Help](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/14):
>
> This is why I recommend looking at the tag quality. In my example I have three tags, ‘Tag 01, Tag 02, and Tag 04’. The processing portion only pays attention to those qualities that are good. [image] numberOfTags = 4 baseTagPath = '[Test]Tag {0:02d}' tagPaths = [baseTagPath.format(i) for i in xrange(1, numberOfTags+1)] valuesIn = system.tag.readBlocking(tagPaths) print 'Tags In' for tag, qVal in zip(tagPaths, valuesIn): print tag, ':', qVal # Processing tagsOut = [] valuesOut = [] for t…

It hadn't really completely hit me how much that helps me till today. I knew it was really helpful, but I didn't realize how much it helps till today.

Thanks so much.

Every single time I look at it, I learn another thing.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [March 10, 2022, 2:46pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/28 "2022-03-10T14:46:15Z")

</div>

Here’s a little line of code you can use when reading tags:

```python
data = [tag.value for tag in system.tag.readBlocking(paths) if tag.quality.good]

```

This gets you directly a list of values, for each tag that has a good quality.  
Obviously, don’t use this if you need to know why a tag’s quality was bad, or if you need the timestamp, etc… but it’s worth it to add as a little wrapper in your lib for when you’re testing things out

---

<div class="post-metadata">

**Author:** ![WillMT10](https://avatars.discourse-cdn.com/v4/letter/w/7feea3/32.png) [@WillMT10](https://forum.inductiveautomation.com/u/WillMT10)\
**Post date:** [March 10, 2022, 2:51pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/29 "2022-03-10T14:51:59Z")

</div>

> [@pascal.fragnoud](#):
>
> `data = [tag.value for tag in system.tag.readBlocking(paths) if tag.quality.good]`

I'm not sure I would recommend this. If a tag quality is not good, you can no longer line up the values in `data` to your tags in `paths`. Could be useful for specific use cases, but might be worth calling out the potential pitfall.

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 10, 2022, 2:56pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/30 "2022-03-10T14:56:52Z")

</div>

For me, that lining up the values is the best part of the share from Jordan, I have to line up so many.

I keep learning things from that post like the xrange thing, I didn’t know about that saving so much memory.

> **[range() vs xrange() in Python - GeeksforGeeks](https://www.geeksforgeeks.org/range-vs-xrange-python/)**
>
> A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

I appreciate this other tip too though.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [March 10, 2022, 3:02pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/31 "2022-03-10T15:02:16Z")

</div>

When all you can are about are the values, to sum them up, average them, or whatever… having this a shortcut to do this is quite handy.

It’s obviously not suited for all situations, like processing each value then writing back to the original tags, but still.  
Even then, you could modify it to include the tag path:

```python
tags = [
	{
		'path': path,
		'value': tag.value
	} for path, tag in zip(paths, system.tag.readBlocking(paths)) if tag.quality.good
]

```

But it kinds of defeat the purpose, which was getting a simple array of values.

Edit: Also, it was a thread about list comprehensions, so… here’s one. or two. ;D

---

<div class="post-metadata">

**Author:** ![WillMT10](https://avatars.discourse-cdn.com/v4/letter/w/7feea3/32.png) [@WillMT10](https://forum.inductiveautomation.com/u/WillMT10)\
**Post date:** [March 10, 2022, 3:20pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/32 "2022-03-10T15:20:35Z")

</div>

Completely fair. I just at least wanted to make sure there was a callout for the pitfall as it is not uncommon for visitors to see a post with code and do a quick copy/paste without really fully understanding the code. Especially since this one can lead to some nasty bugs down the road as it could work fine for retrieving values based on position during testing/production and then fail at a random time in the future when a tag quality is not good (or worse, work without error but grab a value it shouldn’t).

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 10, 2022, 3:44pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/33 "2022-03-10T15:44:16Z")

</div>

You’re saying you can save me time saying:

```auto
numMachines = 18
baseNetTags= '[Test]M{0:02d}/M{0:02d}ProductionData/M{0:02d}Net'
pathsGross = [baseNetTags.format(i) for i in xrange(1,numMachines + 1)]	
valuesIn=system.tag.readBlocking(pathsGross)
valueOut=[]
for x,y in zip(pathsNet,valuesIn):
	if 'Good' in str(y.quality):	 
	 valueOut.append(y.value)
print sum(valueOut)

```

by using this code instead?

```auto
numMachines = 18
baseNetTags='[Test]M{0:02d}/M{0:02d}ProductionData/M{0:02d}Net'
pathsNet = [baseNetTags.format(i) for i in xrange(1,numMachines + 1)]	
netTotal = sum([i.value for i in system.tag.readBlocking(pathsNet) if i.quality.good])
print netTotal

```

the data and the valuesOut would both have a 13th value because the values do not line up to the 18 machines in either case, I think

How does the i.quality.good work?  
I think I understood when it was written like if 'Good" in y  
How is that part of the list known to be quality?

I think the former code was great for teaching me, and this shorter code is good for this specific function.

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 10, 2022, 4:18pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/34 "2022-03-10T16:18:01Z")

</div>

Questions:

1. I can still use system.tag.read, so what is happening when I use it?  
I didn’t understand the part about here:  
[7.9 to 8.1 Upgrade Guide - Ignition User Manual 8.1 - Ignition Documentation](https://docs.inductiveautomation.com/display/DOC81/7.9+to+8.1+Upgrade+Guide)

2. how is the “quality” usable in i.quality.good in the above posts?  
When I print the list, I get the values, but the list also has names of each element or something?  
I don’t know how this is referred to so I am not sure how to look it up.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [March 10, 2022, 4:35pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/35 "2022-03-10T16:35:37Z")

</div>

You can go one step further in this case, and remove the brackets in

```python
netTotal = sum([i.value for i in system.tag.readBlocking(pathsNet) if i.quality.good])

```

`sum` works just fine with generator expressions, so

```python
netTotal = sum(i.value for i in system.tag.readBlocking(pathsNet) if i.quality.good)

```

Will work on the expression without having to create the list.

The `quality` attribute of qualified values has an `isGood()` method that returns true if the quality is good. As @pturmel taught me yesterday, there's some kind of netbeans black magic that allows you to use `.good` instead of `.isGood()`, and that is apparently an optimization.  
It's exactly the same thing as using `tag.value` instead of `tag.getValue()` or `tag.quality` instead of `tag.getQuality()`.  
You can use `.isGood()` if you find the meaning to be clearer (I do). I find it conveys its meaning best when written as `tag.quality.isGood()`.

> [@zacharyw.larson](#):
>
> When I print the list, I get the values, but the list also has names of each element or something?

I'm not sure I understand, so let's go back to the code snippet:

```python
[tag.value for tag in system.tag.readBlocking(paths)]

```

This will iterate through the list of tags returned by `readBlocking`, get the value of each tag, and make a list out of them. You can add a condition to a comprehension, using this syntax:

```python
[element for element in list if condition]

```

In your case, if you want the values of only the qualified values that have a good quality, then that what you check:

```python
[qval.value for qval in qval_list if 'Good' in str(qval.quality)]

```

which can be simplified with

```python
[qval.value for qval in qval_list if qval.quality.isGood()]

```

Edit:  
Wait, I think I got it. No, the resulting list won't have the names of the tags. But the qualified values are still available WHILE iterating through them. If you 'unroll' the comprehension, it might be a bit clearer:

```python
for tag in system.tag.readBlocking(paths):
    if tag.quality.isGood():
        values.append(tag.value)

```

If you want your list to retain the paths, use the other snippet I posted:

```python
tags = [
	{
		'path': path,
		'value': tag.value
	} for path, tag in zip(paths, system.tag.readBlocking(paths)) if tag.quality.good
]

```

This will return a list of dictionaries containing two keys, one for the path, and the other for the value.

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 10, 2022, 4:45pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/36 "2022-03-10T16:45:09Z")

</div>

This is great information

what about the system.tag.read()?

> Questions:
> 
> 1. I can still use system.tag.read, so what is happening when I use it?  
> I didn’t understand the part about here:  
> [7.9 to 8.1 Upgrade Guide - Ignition User Manual 8.1 - Ignition Documentation](https://docs.inductiveautomation.com/display/DOC81/7.9+to+8.1+Upgrade+Guide)

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [March 10, 2022, 4:52pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/37 "2022-03-10T16:52:29Z")

</div>

While they still work, for now, they’re not being maintained, and there’s no guarantee they’ll even be there in 6 months. So save yourself some trouble and just use the new ones.  
Why are they being deprecated ? Maybe their internal code needed some overhaul, I don’t know. But I find they also carry meaning a bit more clearly - there’s no doubt now that `readBlocking` is not asynchronous. I agree that having to pass lists is kind of a pain, but you can quite easily make your own wrappers that get rid of that:

```python
def readTagBlocking(path):
    return system.tag.readBlocking([path])[0]

def writeTagBlocking(path, value):
    return system.tag.writeBlocking([path], [value])[0]

def readTagAsync(path, callback):
    system.tag.readAsync([path], callback)

def writeTagAsync(path, value, callback):
    system.tag.writeAsync([path], [value], callback)

```

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 10, 2022, 5:13pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/38 "2022-03-10T17:13:01Z")

</div>

what if I have two different sets of base tags?  
Like I can do an exception list.  
something like:

```auto
exceptions =[2,4,5,8,9,10,11,12]
nonExceptions = [3,6,14,15,16,17,18]
counterS='NetSCounter'
counterA='NetACounter'
baseTag ='[Test]M{0:02d}/M{0:02d}ProductionData/M{0:02d}{counter}'

pathsNewNet=[baseNetTags.format(i,i,i,k) for i in xrange(1,numMachines + 1)]	

```

well that isn’t right

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [March 10, 2022, 5:17pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/39 "2022-03-10T17:17:33Z")

</div>

I don’t think I understand where you’re getting at…

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 10, 2022, 5:20pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/40 "2022-03-10T17:20:43Z")

</div>

I think I have a situation where I need two for clauses.

I have 18 machines.  
Half of them need to use tags from s-counters and half from a-counters.

So I have to iterate through the 18 machines for my paths  
I also have to set the counter type in the path for each.

I am looking in:

```auto
https://www.geeksforgeeks.org/string-formatting-in-python/
https://www.w3schools.com/python/python_lists_comprehension.asp
https://www.pythonforbeginners.com/basics/list-comprehensions-in-python

```

trying to stitch together a proper list comprehension  
I saw on stackexchange someone recommended two for clauses, but then their example was hard to follow

[Previous page](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621.md?page=1)

[Next page](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621.md?page=3)
