Python List Comprehensions Help

This top post is additional context.

I want to rewrite a huge script.

This first part I was able to figure out with help from community members, in resources listed at the bottom of this post, to get this far. I anticipate that I will need help though, and I will want to reference this later.

First a bunch of reads
The machines are numbered 1-18 and sometimes 15th is just null or not connected, no 13, and 1-9 written as 01-09
example of what was
Machine1gross=system.tag.read("[Facility]folder/subgroup/M01/M01Production/M01Gross")

So I think this becomes like:

numMachinesWith0=9
pathGross=
["Facility]folder/subgroup/M0{}/M0{}Production/M0{}Gross".format(nineSet,nineSet,nineSet) for nineSet in range(1,numMachinesWith0+1)]

it is alive


references for convenience

numComments = 14
pathsComments = ["[Test]SomeTagPath/Comment{}".format(path) for path in range(1,numComments + 1)]
value14Spaces = ["space"]*numComments

for c in range(numComments):
    print "commentPath: ",pathsComments[c], " ","value:" , value14Spaces[c]

Python guide for list comprehensions

list comprehensions w3 schools

https://forum.inductiveautomation.com/t/tag-writeblocking-multiple-tags-to-one-value

Right now I am doing a list comprehension for 1-9
and I plan to do another for 10-18
however I am looking up how to say like not 13

Is it best to do these in parts?

and I wonder what will happen to my script if 15 doesn’t exist sometimes
Will my script fail if a path results in null or a bad expression tag?

You can easily exclude items from a list comprehension like this:

exclusions = [13,15]
print [x for x in range(1,17) if x not in exclusions]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16]

2 Likes

what about the 0?

01, 02, …09
10, 11, …18

exclusions = [13,15]
numbers = [x for x in range(1,17) if x not in exclusions]
print ["tag{:0>2}".format(x) for x in numbers]
['tag01', 'tag02', 'tag03', 'tag04', 'tag05', 'tag06', 'tag07', 'tag08', 'tag09', 'tag10', 'tag11', 'tag12', 'tag14', 'tag16']

2 Likes

Might want to do a little more research on string.format()

To add a leading 0 to decimal with less than 2 digits you can use:

print ['path{:02d}'.format(path) for path in range(10)]

You can also use a number designation in the format so it becomes:

print ['path{0:02d}'.format(path) for path in range(10)]

Combining that with what @witman has shown:

numMachines = 18
exclusions = [13,15]
pathsGross = ['[Facility]folder/subgroup/M{0:02d}/M{0:02d}Production/M{0:02d}Gross'.format(nineSet) for nineSet in range(1,numMachines + 1) if nineSet not in exclusions]
4 Likes

Thanks

I am reading about string.format()

w3 schools string format

gfg string formatting

I am still reading this one, it is huge, but I have not seen notes on {0:02d} yet, so I am really happy you showed me it
gfg string format method

I don’t want to exclude 15

I know 15 will sometimes not be connected, so the tags will be bad

Can I just include it? Will reading a bad tag error the script?
Or do I need to check if these values are all null before I do reads?

in some conditions, I will be writing these values to tags later in my script

It won’t give you an error, but you should be able to check the quality of the tags after you read them.

2 Likes

On a side note because it has helped me a lot check out Catalog Home | Codecademy they have a decent amount of free lessons, editor + console to test and see live results. You learn by doing which I really like. they have tips and good instructions.

I am trying to use \n to make a new line

the script console keeps typing \n as part of the string

I thought maybe this was Python in Ignition

Says that is it should work though.
https://docs.inductiveautomation.com/display/DOC81/Strings

I am trying to edit this and upload an image. It is just spinning at 0%

test=["[this]M{0:02d}/M{0:02d}Production/M{0:02d}Gross\n".format(nineSet) 
for nineSet in range(1,numMachinesWith0+1)]
test
['[this]M01/M01Production/M01Gross\n', '[this]M02/M02Production/M02Gross\n', '[this]M03/M03Production/M03Gross\n',.....

how are you trying to display it?

s = '1\n2\n3'

s

print s

Output:

'1\n2\n3'
1
2
3
>>>
1 Like

I edited above with poor timing. Sorry.
I was trying to get a new line incorrectly.
Thanks for your example


Your example gave me the idea

input

numMachinesWith0=18
test=["[this]M{0:02d}/M{0:02d}Production/M{0:02d}Gross".format(nineSet) 
for nineSet in range(0,numMachinesWith0+1)]
test[0]
test[1]
test[18]

output

'[this]M00/M00Production/M00Gross'
'[this]M01/M01Production/M01Gross'
'[this]M18/M18Production/M18Gross'

I think this is good because machine number is equal to the index number when reading.
Maybe it is better to exclude 0 and 13. I have yet to see.

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 tag, qValue in zip(tagPaths, valuesIn):
	if 'Good' in str(qValue.quality):
		tagsOut.append(tag)
		valuesOut.append(qValue.value + 5)
		
print 'Tags Out'
for tag, val in zip(tagsOut, valuesOut):
	print tag, ':', val
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 tag, qValue in zip(tagPaths, valuesIn):
	if 'Good' in str(qValue.quality):
		tagsOut.append(tag)
		valuesOut.append(qValue.value + 5)
print '\n-----------\n\nTags Out'		
for tag, val in zip(tagsOut, valuesOut):
	print tag, ':', val

Output

>>> 
Tags In
[Test]Tag 01 : [10, Good, Mon Feb 28 15:11:26 EST 2022 (1646079086152)]
[Test]Tag 02 : [20, Good, Mon Feb 28 15:11:28 EST 2022 (1646079088784)]
[Test]Tag 03 : [null, Bad_NotFound("Path '[Test]Tag 03' not found."), Wed Feb 16 12:47:37 EST 2022 (1645033657329)]
[Test]Tag 04 : [40, Good, Mon Feb 28 16:05:57 EST 2022 (1646082357934)]

-----------

Tags Out
[Test]Tag 01 : 15
[Test]Tag 02 : 25
[Test]Tag 04 : 45
>>> 
1 Like

Thanks for showing how the tag quality check can help.
I appreciate it.

1 Like

Should note, that you don't need the 0 in range(). The start parameter is 0 by default.


#range(start,stop,step)
# start - An integer number specifying at which position to start. Default is 0 (optional)
# stop - An integer runber specifying at which position to stop. Stop is not included in the returned set.
# step - An integer number specifying the incrementation. Default is 1 (optional)

print range(10)
print range(1,11)
print range(1,20,2)

Output

>>>
[0,1,2,3,4,5,6,7,8,9]
[1,2,3,4,5,6,7,8,9,10]
[1,3,5,7,11,13,15,17,19]
>>>

Sometimes we take the range syntax for granted, it isn't always straight forward all that you can accomplish with it.

Other examples of this are the enumerate() and zip() functions which are not used as often but can come in handy when you need it.

https://docs.python.org/2.7/library/functions.html#enumerate
https://docs.python.org/2.7/library/functions.html#zip

1 Like

Thanks
I like to say (0,variable+1) for the moment.

I am reading again about the tag provider and tag browser too.
I am building a ship in a bottle without the config access so that nothing I do impacts other hubs.
I really appreciate the tag provider made in the example.

I have a silly question that I am not sure how to look up.
If a script runs once very 50 seconds as a gateway timer script, what is the best way to instead just run it at certain times like at the end of a shift and an hour after the end of a shift?

Look into Gateway Scheduled Scripts.

2 Likes

8.1.0 unfortunately

image

I would definitely update to 8.1.14 if at all possible