Python boolean list with fixed-ordered elements - python

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)

Related

I've got an object that is basically an int with some extra properties. Can I coerce it into an int when it's used as a list index?

Context: I'm making a game that happens in a maze made of square tiles and almost everything, from movement to attacks, involves directions, which are mostly used to index lists. Subtracting or adding to directions is an easy way to turn left or right, but I always have to check that they are still within bounds, and I would like to automate that by making a custom class.
Here is how I'm currently doing it:
global UP
UP = 0
global RIGHT
RIGHT = 1
global DOWN
DOWN = 2
global LEFT
LEFT = 3
And here is what I'd like to do:
class Direction:
number_of_directions=4
def __init__(self,direction):
self.direction = direction
def __int__(self):
return self.direction
def __add__(self,other): #Here other is supposed to be an int
return (self.direction + other)%number_of_directions
def __sub__(self,other): #Here other is supposed to be an int
return (self.direction - other)%number_of_directions
global UP
UP = Direction(0)
global LEFT
LEFT = Direction(1)
global DOWN
DOWN = Direction(2)
global RIGHT
RIGHT = Direction(3)
The only problem with that is that I am using UP, RIGHT, etc. as indexes, like I have a Tile that has a list of four Wall and I constantly call Tile.walls[direction] with direction being one of my four constants, and I don't want to have to specify Tile.walls[int(direction)] everytime.
Is there a way to have direction automatically coerced into an int whenever it's used for indexing?
you could use an IntEnum:
from enum import IntEnum
from numbers import Integral
class Direction(IntEnum):
UP = 0
RIGHT = 1
DOWN = 2
LEFT = 3
_NB_DIRECTIONS = 4
def __add__(self, other):
if isinstance(other, Integral):
return Direction((self.value + other) % Direction._NB_DIRECTIONS)
return NotImplemented
def __sub__(self, other):
if isinstance(other, Integral):
return Direction((self.value - other) % Direction._NB_DIRECTIONS)
return NotImplemented
those are subclasses of int and can be used e.g. as indices for lists:
lst = list(range(4))
print(lst[Direction.LEFT]) # -> 3
the examples you give work like this:
print(Direction.UP) # Direction.UP
print(Direction.UP + 1) # Direction.RIGHT
print(Direction.UP - 1) # Direction.LEFT
print(Direction.UP + 10) # Direction.DOWN
a = Direction.UP
a += 1
print(a) # Direction.RIGHT
print(Direction.UP) # Direction.UP
print(type(a)) # <enum 'Direction'>
b = 1
print(type(b)) # <class 'int'>
b += Direction.UP
print(b) # 1
print(type(b)) # <class 'int'>
print(Direction.DOWN - 1 == Direction.UP + 1) # True
lst = ["zero", "one", "two", "three"]
print(lst[Direction.DOWN]) # 'two'
print(lst[Direction.UP + 3]) # 'three'
print(lst[Direction.LEFT - 2]) # 'one'
Yes, simply define __index__(). For example:
class Direction:
def __init__(self, direction):
self.direction = direction
def __index__(self):
return self.direction
UP = Direction(0)
cardinals = ['north', 'east', 'south', 'west']
print(cardinals[UP]) # -> north
This also makes __int__ unnecessary since __index__ is used as a fallback.
print(int(UP)) # -> 0
P.S. For this answer, I'm ignoring any design considerations. Using an IntEnum might be a better solution, I'm not sure.
I got my code to work by making Direction a subclass of int.
Here is what my current code looks like:
global NB_DIRECTIONS
NB_DIRECTIONS = 4
(This part is a bit superfluous, just in case I want to adapt the game with, say, hexagons or triangles instead of squares later on. The real code starts now.)
class Direction(int):
directions = NB_DIRECTIONS
def __init__(self,direction):
self.direction = direction
def __add__(self,other):
if isinstance(other,int):
return Direction((self.direction+other)%self.directions)
return NotImplemented
def __radd__(self,other):
if isinstance(other,int):
return Direction((other+self.direction)%self.directions)
return NotImplemented
def __sub__(self,other):
if isinstance(other,int):
return Direction((self.direction-other)%self.directions)
return NotImplemented
def __rsub__(self,other):
return NotImplemented
def __eq__(self, other):
if isinstance(other,Direction):
return self.direction == other.direction
return NotImplemented
global UP
UP=Direction(0)
global RIGHT
RIGHT=Direction(1)
global DOWN
DOWN=Direction(2)
global LEFT
LEFT=Direction(3)
(I made the addition be between a Direction object and an int, not between two Direction object, because it makes more sens for what I'm doing, but that's irrelevant to the problem of indexing I was trying to solve.)
Let's look at my Direction's behavior:
>>> UP
0
>>> UP+1
1
>>> UP-1
3
>>> UP+10
2
>>> a=UP
>>> a+=1
>>> a
1
>>> UP
0
>>> type(a)
<class '__main__.Direction'>
>>> b=1
>>> type(b)
<class 'int'>
>>> b+=UP
>>> b
1
>>> UP
0
>>> type(b)
<class '__main__.Direction'>
>>> DOWN-1==UP+1
True
>>> lst=["zero","one","two","three"]
>>> lst[DOWN]
'two'
>>> lst[UP+3]
'three'
>>> lst[LEFT-2]
'one'
>>> type(RIGHT)
<class '__main__.Direction'>
TL;DR:
I made my class inherit from int, now it can be used as an index.

how to add this both original_text and reversed_text attributes in this class? how should I fix it to get the ideal outputs?

Below are the ideal outputs:
'''
>>> palindrome = Palindrome('eye')
>>> palindrome.original_text
'eye'
>>> palindrome.reversed_text
'eye'
>>> palindrome.is_palindrome()
True
>>> palindrome = Palindrome('dye')
>>> palindrome.original_text
'dye'
>>> palindrome.reversed_text
'eyd'
>>> palindrome.is_palindrome()
False
'''
My code:
class Palindrome :
def __init__(self,number) :
self.num = number
def is_palindrome(self) :
temp = self.num
result = 0
while(temp != 0) :
rem = temp % 10
result = result * 10 + rem
temp //= 10
if self.num == result :
return True
else :
return False
How to add this both original_text and reversed_text attributes in this class?
How should I fix the code above to obtain the ideal results?
You can use python's built-in power to make your code more readible and simple. Something like this should work:
class Palindrome :
def __init__(self, data):
data = str(data)
self.original_text = data
self.reversed_text = data[::-1]
def is_palindrome(self):
return self.original_text == self.reversed_text
palindrome = Palindrome('eye')
print(palindrome.original_text)
print(palindrome.reversed_text)
print(palindrome.is_palindrome())
palindrome = Palindrome('dye')
print(palindrome.original_text)
print(palindrome.reversed_text)
print(palindrome.is_palindrome())

Context aware function

I have a piece of code below:
// The only difference is grad
class TestOne(...):
def init(self):
self.input_one = tr.allocate( ..., grad = False)
self.input_two = tr.allocate( ..., grad = False)
class TestTwo(...):
def init(self):
self.input_one = tr.allocate( ..., grad = True)
self.input_two = tr.allocate( ..., grad = False)
class TestThree(...):
def init(self):
self.input_one = tr.allocate( ..., grad = False)
self.input_two = tr.allocate( ..., grad = True)
Test1 = TestOne()
Test2 = TestTwo()
Test3 = TestThree()
# definition of allocate. It is a wrapper of the PyTorch randn function
# https://pytorch.org/docs/stable/torch.html#torch.randn
def allocate(..., grad):
...
return torch.randn(..., require_grad=grad)
I want to reduce the duplicate code by implementing just one class but able to generate same objects as the code above.
class Test(...):
// how to make it return different values?
def auto_set(self):
return False
def init(self):
self.input_one = tr.allocate( ..., grad = self.auto_set())
self.input_two = tr.allocate( ..., grad = self.auto_set())
Test1 = Test()
# grad of input_one and input_two will be `False, False`
Test2 = Test()
# grad of input_one and input_two will be `True, False`
Test3 = Test()
# grad of input_one and input_two will be `False, True`
This is part of a big project, so I can't change the interface of the init function. There could be N number of inputs which would require N + 1 different classes. That is not a scalable implementation so want to find a solution to solve that.
PS: My previous question was causing too many confusions to others so I changed it hoping to clarify on what I really want to have.
Just posting my solution here:
class Test(object):
init_counter = 0
num_variable = 0
def increase_init_counter(self):
Test.init_counter += 1
Test.auto_set_counter = 0
def auto_set(self):
if Test.init_counter == 0:
Test.num_variable += 1
return False
else:
print ("init_counter: {}, auto_set_counter: {}".format(Test.init_counter, Test.auto_set_counter))
Test.auto_set_counter += 1
if Test.init_counter == Test.auto_set_counter:
return True
else:
return False
def init(self):
self.A = self.auto_set();
self.B = False;
self.C = self.auto_set();
print ("A: {}, B: {}, C: {}".format(self.A, self.B, self.C))
=== Test
TestA = Test()
TestA.init()
for _ in range(TestA.num_variable):
TestB = copy.deepcopy(TestA)
TestB.increase_init_counter()
TestB.init()
If you find yourself using numbered variable names (e.g. v1, v2, v3) you need to stop immediately and think "Should I use a list instead?" - and the answer is "yes" in almost all cases.
Other notes:
To pick random values, make a list of possible values (in this case, [True, False]) and use random.choice()
range() can make a list of N values, which we can use to make another list of random choices (see "list comprehension" when you don't understand the [x for x in iterable] syntax).
Classes have __init__ as the constructor, you don't need a manual init function.
Classes should use a capital letter at the start of their name.
Code:
from random import choice
class Test(object):
def __init__(self, num_values):
self.values = [choice([True, False]) for _ in range(num_values)]
def see(self):
print(self.values)
for _ in range(3):
test1 = Test(3)
test1.see()
prints something like:
[False, False, False]
[True, False, True]
[True, True, False]
Let's see IIUYC...:
What you can do is to add a global, or let's say better common variable to the class definition, which is incremented when instanciating new objects of that class (and perhaps also better decremented when they are deleted).
This would give you the opportunity to implement different behaviuors of __init__() depending on the number of objects already created before.
Imagine a test class like
class Test():
i = 0
def __init__(self):
Test.i += 1
def __del__(self):
Test.i -= 1
After creating a first object, the common counter is 1:
t1 = Test()
t1.i
1
After creating a second object, the common counter is 2:
t2 = Test()
t2.i
Out: 2
... in all existing objects, because it's a common counter:
t1.i
Out: 2
Some sample implementation of what I think you want to achieve:
class Test():
i = 0
def __init__(self):
self.A = bin(Test.i)[-1] == '1'
self.B = bin(Test.i)[-2] == '1'
Test.i += 1
def __del__(self):
Test.i -= 1
t1 = Test()
print(t1.i, t1.A, t1.B)
# 1 False False
t2 = Test()
print(t2.i, t2.A, t2.B)
# 2 True False
t3 = Test()
print(t3.i, t3.A, t3.B)
# 3 False True
First of all, I suspect that what you need is a list of instance attributes (the variables in each object of the type).
class test(object):
def __init__(self):
self.v = []
# how to make it return different values?
def auto_set(self):
return False
def init(self):
self.v.append(self.auto_set())
def see(self):
print (self.v)
for _ in range(3):
test1 = test()
test1.init()
test1.see()
This will allow you to add to the attribute list. Is that enough to get you moving? We can't suggest a more thorough solution until you explain your system better.

How to implementation linear search in String Class Python

I want to search for specific characters in a string list. For example, string_list = ['sasasd']; I want to search for 'sa'. The linear function will return True, but I tried many times, It can not return True.
class String:
def __init__(self, str_value = []):
self.value = str_value
def search_data(self,target_value):
m = len(self.value)
for i in range(m):
if self.value[i] == target_value:
return True
return False
value_data = ['dasdasd']
my_str = String(value_data)
result = my_str.search_data('da')
print(result)
You have a few problems in your code.
str_value is a list and you initialize the value of the class attribute like this: self.value = str_value. So, when you give it the value ['dasdasd'], you end up having a list with one string element.
When declaring the m variable, m = len(self.value), you compute the number of elements from that list NOT the number of characters from the string value inside the list (m = len(['dasdasd']) = 1).
Also, the for that searches for the target_value string inside the self.value string is incorrect.
Quick fix to correct the current code:
class String:
def __init__(self, str_value = []):
self.value = str_value
def search_data(self, target_value):
# assumption here that self.value has the format: ['string'] (list with 1 string element)
if self.value[0].find(target_value) == 0:
return True
return False
value_data = ['dasdasd']
my_str = String(value_data)
result = my_str.search_data('da')
print(result)
Tested and it outputs True.

Moving from one enum state to the next and cycling through

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

Categories

Resources