Moving from one enum state to the next and cycling through - python

I simply have enumerator with 3 modes ledOn, ledBlink, ledOFF and I have a variable mode that keeps track of modes for particular object. So for example I have one LED starting in mode ledOn i would like to for example after 5 seconds move to the next element which would be ledBlink then to ledOFF and then cycle through to ledON is there an easy way to achieve something like this?
import time
from threading import Thread
from enum import Enum
class ledController(Thread):
ledModes = Enum('ledModes', 'ledON ledBlink ledOFF')
def __init__(self, GPIOID, state=False, blinkDuration=2, mode=ledModes.ledON):
self.GPIOID = GPIOID
self.state = state
self.blinkDuration = blinkDuration
self.mode = mode
self.blinked = False
Thread.__init__(self)
def run(self):
if(self.mode == self.ledModes.ledON):
self.ledON()
if(self.mode == self.ledModes.ledBlink):
self.ledBlink()
if(self.mode == self.ledModes.ledOFF):
self.ledOFF()
time.sleep(self.blinkDuration)
self.mode.next()
def ledSwitch(self):
self.state = not self.state
print(self.ledDetails())
def ledON(self):
self.state = True
print(self.ledDetails())
def ledOFF(self):
self.state = False
print(self.ledDetails())
def ledBlink(self, duration):
self.ledON()
print(self.ledDetails())
time.sleep(self.Blinkduration)
self.ledOFF()
print(self.ledDetails())
time.sleep(self.Blinkduration)
def ledDetails(self):
return "Thread: "+self.getName()+", LED: "+str(self.GPIOID)+", State: "+str(self.state)+", Mode: "+str(self.mode.name)+", Blink duration: "+str(self.blinkDuration)
redLED = ledController(17, blinkDuration = 3)
blueLED = ledController(18, mode = ledController.ledModes.ledOFF)
redLED.setName('1')
blueLED.setName('2')
redLED.start()
blueLED.start()
redLED.join()
blueLED.join()

I would just use itertools.cycle instead of your enum:
>>> from itertools import cycle
>>> ledModes = cycle(['ledON', 'ledBlink', 'LedOFF'])
>>> first = next(ledModes)
>>> second = next(ledModes)
>>> third = next(ledModes)
>>> fourth = next(ledModes)
>>>
>>> first
'ledON'
>>> second
'ledBlink'
>>> third
'LedOFF'
>>> fourth
'ledON'
>>>
FYI, you can either do next(ledModes) or ledModes.next(), both are doing the same.
EDIT: You could use something like this, as method of your class:
from itertools import cycle
def initialize_cycle(start_mode):
states = ['ledON', 'ledBlink', 'ledOFF']
if start_mode not in states:
raise ValueError('start_mode invalid')
iterable = cycle(states)
for _ in states[:states.index(start_mode)]:
iterable.next()
return iterable
test1 = initialize_cycle('ledON')
test2 = initialize_cycle('ledOFF')
test3 = initialize_cycle('ledBlink')
# validation
for test in test1, test2, test3:
for _ in range(5):
print test.next()
print '-' * 20
Output:
$ python cycle.py
ledON
ledBlink
ledOFF
ledON
ledBlink
--------------------
ledOFF
ledON
ledBlink
ledOFF
ledON
--------------------
ledBlink
ledOFF
ledON
ledBlink
ledOFF
--------------------

The easiest fix for your current code is to:
change your run method, and
add a next_mode method:
like so:
def run(self):
while True:
set_mode = getattr(self, self.mode)
set_mode()
time.sleep(self.blinkDuration)
self.next_mode()
def next_mode(self):
self.mode = {
self.ledModes.ledON: self.ledModes.ledBlink,
self.ledModes.ledBlink: self.ledModes.ledOFF,
self.ledModes.ledOff: self.ledModes.ledOn,
}[self.mode]

Probably an overkill:
import itertools
class EnumCycler(object):
def __init__(self, enum, start_at=None):
self.enum = enum
self.members = list(enum.__members__.values())
self.start_at = self.members[0] if start_at is None else start_at
self.cycles = 0
def __iter__(self):
cycle = itertools.cycle(self.members)
sanity_check = len(self.members)
for value in cycle:
if sanity_check:
if value != self.start_at:
sanity_check -= 1
continue
sanity_check = 0
self.cycles += 1
yield value
Then:
>>> mode = Enum('ledModes', 'ledON ledBlink ledOFF')
>>> led_mode_cycler = EnumCycler(mode, start_at=mode.ledOFF)
>>> for value in led_mode_cycler:
... print(led_mode_cycler.cycles, value)
... if led_mode_cycler.cycles >= 10: break # infinite loop if we never break off
1 ledModes.ledOFF
2 ledModes.ledON
3 ledModes.ledBlink
4 ledModes.ledOFF
5 ledModes.ledON
6 ledModes.ledBlink
7 ledModes.ledOFF
8 ledModes.ledON
9 ledModes.ledBlink
10 ledModes.ledOFF

Related

Python: Objects initialized the same way affect each other

I'm creating a class like the following in Python:
stat_list = ['Health', 'Strength', 'Stamina']
empty_stats = dict.fromkeys(stat_list, 0)
class Stats:
def __init__(self, stat_dict=None):
if stat_dict is None:
stat_dict = empty_stats
self.stat_dict = stat_dict
self.fill_stat_dict()
def fill_stat_dict(self):
for stat in stat_list:
if stat not in self.stat_dict:
self.stat_dict[str(stat)] = 0
def increase_stat(self, stat, amount):
if stat in self.stat_dict.keys():
self.stat_dict[stat] += amount
def sum_stat(self):
return sum(self.stat_dict.values())
So far, so good, but I bumped into the following issue:
blank1 = Stats()
print(blank1.sum_stat())
blank2 = Stats()
print(blank2.sum_stat())
not_blank = Stats({'Stamina': 4})
print(not_blank.sum_stat())
blank2.increase_stat('Health', 2)
print(blank1.sum_stat())
print(blank2.sum_stat())
print(not_blank.sum_stat())
output:
0
0
4
2
2
4
I would want blank1 and blank2 to be separate objects of the Stats class initially created empty that can be modified independently. But what I'm seeing here is that modifying blank1 affects blank2, while not_blank remains independent. What am I doing wrong?
dictionary's are passed by reference which means that empty_stats is being modified by Stats, try changing the line so that it makes a new copy
...
def __init__(self, stat_dict=None):
if stat_dict is None:
stat_dict = empty_stats.copy()# <- change this
self.stat_dict = stat_dict
self.fill_stat_dict()
...

Python - Update a function/return assigned to a var

Code first so you'll understand what I'm talking about :
goal = False
count = 0
def function():
if goal==True:
return True
else:
return False
def func():
if dict1["A"]==True:
return True
else:
return False
dict1 = {"A":function()}
dict2 = {"B":func()}
list = [dict1,dict2]
goal = True
for i in list:
count = 0
for x,y in i.items():
if y==True:
count+=1
if count==len(i):
print("Works")
else:
print(i)
>>>{"A":False}
>>>{"B":False}
This is not my current code, but it is the actual issue. This is where I'm asking, how can I update the values in the dicts. Should I do something like :
for i in list:
for x,y in i.items():
y()
?
My current project is used in Ren'Py (.rpy) but as I'm using python blocks, the code works exactly as normal Python.
Within a class named Event, my elements are exactly as it follows:
def ev_check(self):
if self.done==False:
self.count = 0
for x,y in self.conditions.items():
if y==True:
self.count+=1
else:
pass
if self.count==len(self.conditions):
self.valid = True
else:
self.valid = False
else:
self.valid = False
def own_office():
if Promotion_1.done==True: #Once the event is played, .done gets True
return True
else:
return False
def times_worked(x):
if You.worked < x:
return False
else:
return True
Promotion_1.conditions = {"Work 2 times" : times_worked(2)}
Meet_Tigerr.conditions = {"Own office" : own_office()}
#External event that adds a value to the data named You.worked to get it to 2
print(Promotion_1.conditions["Work 2 times"])
>>> False
Expected result : True
Result : False
You can create your custom dict and have this feature. You may try something like this:
class MyDict(dict):
def __getitem__(self, item):
val = super().__getitem__(item)
if callable(val):
return val()
return val
It will work exactly like a dict, except that it will call the callable values for you every time.
d = MyDict()
d['m'] = 1
d['m']
Out[28]: 1
task
Out[33]: <function __main__.task()>
task()
Out[34]: True
d['t'] = task
d['t']
Out[36]: True
EDITED : Modified the code a bit to show how you can even have argument values passed for your parameterized functions:
def func():
return True
def param_func(i):
return 2*i
def param_func2(i, j):
return i*j
class MyDict(dict):
def __getitem__(self, key):
if isinstance(key, tuple):
super_key = key[0]
else:
super_key = key
super_val = super().__getitem__(super_key)
if callable(super_val):
if isinstance(key, tuple):
args = key[1:]
return super_val.__call__(*args)
else:
return super_val.__call__()
return super_val
if __name__ == "__main__":
d = MyDict()
d['num'] = 1
print(d['num'])
d['func'] = func
print(d['func'])
d['param_func'] = param_func
print(d['param_func', 2])
d['param_func2'] = param_func2
print(d['param_func2', 2, 6])
Output :
1
True
4
12

itertools 'previous' (opposite of next) python

I'm currently using something like
>> import itertools
>> ABC = [a, b, c]
>> abc = itertools.cycle( ABC )
>> next( abc )
a
>> next( abc )
b
>> next( abc )
c
I want my next call to be
>> previous( abc )
b
Is there a method in itertools that can accomplish this?
No, there isn't.
Because of the way Python's iteration protocol works, it would be impossible to implement previous without keeping the entire history of the generated values. Python doesn't do this, and given the memory requirements you probably wouldn't want it to.
You can use deque from collections module and rotate method,
for example:
from collections import deque
alist=['a','b','c']
d=deque(alist)
current = d[0]
print(current) # 'a'
d.rotate(1) # rotate one step to the right
current = d[0]
print(current) # 'c'
d.rotate(-1) # rotate one step to the left
current = d[0]
print(current) # 'a' again
You can write your own class to emulate an iterable object with next and previous. This is the simplest implementation:
class cycle:
def __init__(self, c):
self._c = c
self._index = -1
def __next__(self):
self._index += 1
if self._index>=len(self._c):
self._index = 0
return self._c[self._index]
def previous(self):
self._index -= 1
if self._index < 0:
self._index = len(self._c)-1
return self._c[self._index]
ABC = ['a', 'b', 'c']
abc = cycle(ABC)
print(next(abc))
print(next(abc))
print(next(abc))
print(abc.previous())
Although deque is the way to go, here's another example:
Code
import itertools as it
class Cycle:
"""Wrap cycle."""
def __init__(self, seq):
self._container = it.cycle(seq)
self._here = None
self.prev = None
def __iter__(self):
return self._container
def __next__(self):
self.prev = self._here
self._here = next(self._container)
return self._here
Demo
c = Cycle("abc")
next(c)
# 'a'
next(c)
# 'b'
c.prev
# 'a'

Python boolean list with fixed-ordered elements

I am trying to make some binary singal system by boolean variables I named with LIGHTx.
LIGHT1 = True
LIGHT2 = True
LIGHT3 = False
LIGHT4 = False
Next, I nest these variables into a list for future calculation,
signal = [LIGHT1, LIGHT2, LIGHT3, LIGHT4]
Currently I am using the idea from Python: Boolean List to Binary String and Convert base-2 binary number string to int to convert the list to int number which is my signal. Here, [1,1,0,0] means 12.
In [97]: boolList2BinString(signal)
Out[97]: 12
My questions are:
How can I automatically updating the elements of "signal" by updating the value of the LIGHTs, rather than running signal = [LIGHT1, LIGHT2, LIGHT3, LIGHT4] again and again? Whitch means, in the rest of my codes, I only need to run LIGHTx = xxxx and boolList2BinString(signal). (Maybe some way like pointer of C++ ?)
If it is impossible with question 1, is there any way that I can fix the order of the LIGHTs in the list?
[Update]
Please exclude the way that building the 'signal' list inside the 'boolList2BinString' function.
Original:
def boolList2BinString(lst):
return int('0b' + ''.join(['1' if x else '0' for x in lst]), 2)
Building inside:
def boolList2BinString():
osignal = [LIGHT1 , LIGHT2 , LIGHT3 , LIGHT4 ]
return int('0b' + ''.join(['1' if x else '0' for x in signal ]), 2)
Thanks in advance!
you can create a class to hold the boolean, then it would act like a pointer
>>> class Light:
... def __init__(self, value):
... self.value = value
... def get(self):
... return(self.value)
... def set(self, value):
... self.value = value
then use light.get() to get the value, or light.set() to set the value
>>> Light1 = light(True)
>>> Light2 = light(False)
>>> lights = [light1, light2]
>>> for l in lights:
... print(l.get())
...
True
False
example showing set:
>>> for l in lights:
... print(l.get())
...
True
False
>>> light2.set(True)
>>> for l in lights:
... print(l.get())
...
True
True
>>>
Perhaps you just need some sort of wrapper.
class Light(object):
def __init__(self, state):
self.state = state
def false(self):
self.state = False
def true(self):
self.state = True
LIGHT1 = Light(True)
LIGHT2 = Light(True)
LIGHT3 = Light(False)
LIGHT4 = Light(False)
signal = [LIGHT1, LIGHT2, LIGHT3, LIGHT4]
And then you simply can change states of each lights as LIGHT1.true() or LIGHT1.false() and value in signal list will be changed automatically.
LIGHT1.false()
LIGHT1.state # False
LIGHT1.true()
LIGHT1.state # True
The methods naming could be changed, of course.
You could use a special property class to set bits in an integer.
Here is an example:
class Light(property):
def __init__(self, rank):
self.rank= rank
super(Light, self).__init__(self._get, self._set)
def _get(self, signal):
return (signal.value & (1 << self.rank)) != 0
def _set(self, signal, value):
if value:
signal.value |= 1 << self.rank
else:
signal.value &= ~(1 << self.rank)
class Signal(object):
def __init__(self, value=0):
self.value = value
l1 = Light(3)
l2 = Light(2)
You can then use that simply:
>>> s = Signal()
>>> s.value
0
>>> s.l1
False
>>> s.l1 = True
>>> s.l1
True
>>> s.value
8
(Tested on both Python 2.7 and Python 3.5)

Initializing Class instance within a class

the entire counter list of methods in side counter class do not work. I want setcap to set of cap, and check cap to see if each counter have reached their limit as hr min sec are what a clock should know i would like to initialize them inside the clock.
import time
class counter():
count = 0
cap = 0
def _init_(self):pass
def reset(self):
self.count = 0
def increment(self):
self.count += 1
def setcap(self,x):
print x
self.cap = x
def checkcap(self):
if self.cap > self.count:
return False
else:
return True
class clock():
_hr = counter()
_min = counter()
_sec = counter()
def _init_(self):
self._hr.setcap(23)
self._min.setcap(59)
self._sec.setcap(59)
def manualreset(self):
self._hr.reset()
self._min.reset()
self_sec.reset()
def tick(self):
if self._sec.checkcap():
self._sec.reset()
self._min.increment()
if self._min.checkcap():
self._min.reset()
self._hr.increment()
if self._hr.checkcap():
self._hr.reset()
else:
self._sec.increment()
newClock = clock()
raw_input("Press enter to start clock")
while newClock._hr != 24:
newClock.tick()
print str(newClock._hr.count).zfill(2) + str(newClock._min.count).zfill(2) + str(newClock._sec.count).zfill(2)
One of the problems in your code is that your init functions are init.
Try using
def __init__(self):
pass
This should solve one of your problems

Categories

Resources