Reputation: 309
I have a functioning piece of code that suits my purposes but I wasn't sure if there was a better way to meet the end I am looking for. Here is my code :
def eitherOne(image1, image2):
curIm1 = pyautogui.locateOnScreen(image1)
curIm2 = pyautogui.locateOnScreen(image2)
while curIm1 == None or curIm2 == None:
curIm1 = pyautogui.locateOnScreen(image1)
curIm2 = pyautogui.locateOnScreen(image2)
if curIm1 != None:
x, y = pyautogui.center(curIm1)
pyautogui.click(x,y)
if curIm2 != None:
x, y = pyautogui.center(curIm2)
pyautogui.click(x,y)
What this is doing is looking for one of two images and then clicking on whichever ends up being true. Is there any method or function I can use that can determine which of the conditions around the "or" returned true without running a subsequent set of "if" operations? Even if the answer is "No, you need the if statements" I'd appreciate it so I am not going on a wild goose chase for no reason.
Thank you for your time!
Upvotes: 0
Views: 100
Reputation: 23743
A v2.7 example of @tobias_k's comment to your question. In Boolean Operations, the value of the True
espresion is returned.
class Img(object):
def __init__(self, name):
self.name = name
def __bool__(self):
return True
c1 = Img('c1')
c2 = None
current_image = c2 or c1
if current_image:
print(current_image.name)
else:
print('None')
In this example, c1
is assigned to current_image
because it evaluates to True
and its name
is printed.
Upvotes: 1
Reputation: 530940
I'd probably do something like this. You create an infinite loop that repeatedly tries one image, then the other, breaking once one of them suceeds.
def eitherOne(image1, image2):
images = itertools.cycle([image1, image2])
for img in images:
curIm = pyautogui.locateOnScreen(img)
if curIm is not None:
break
x, y = pyautogui.center(curIm)
pyautogui.click(x, y)
If you prefer a while
loop to a for
loop,
def eitherOne(image1, image2):
images = itertools.cycle([image1, image2])
curIm = None
while curIm is None:
curIm = pyautogui.locateOnScreen(next(images))
x, y = pyautogui.center(curIm)
pyautogui.click(x, y)
Or, you can do more with itertools
to avoid an explicit loop altogether.
from itertools import cycle, imap, dropwhile
def eitherOne(image1, image2):
curIm = next(dropwhile(lambda x: x is None,
imap(pyautogui.locateOnScreen,
cycle([image1, image2]))))
x, y = pyautogui.center(curIm)
pyautogui.click(x, y)
(I'm mildly surprised you can't use None
as the predicate to dropwhile
, similar to how you can with filterfalse
.)
Update: actually, since filter
and map
already return iterators in Python 3, there's no need to use dropwhile
and imap
:
def eitherOne(image1, image2):
curIm = next(filter(None,
map(pyautogui.locateOnScreen,
cycle([image1, image2]))))
x, y = pyautogui.center(curIm)
pyautogui.click(x, y)
Bonus content!
To take the functional approach to an extreme, you could write the following in coconut:
def eitherOne(image1, image2) = ([images1, images2] |>
cycle |>
map$(pyautogui.locateOnScreen) |>
filter$(None) |>
next |>
pyautogui.center |*>
pyautogui.click)
Upvotes: 3