I have a generator function that tracks whether I am between a certain pair of events-- a "start" event and an "end" event. For example, it could be examining tokens and reporting whether I am between the comment delimiters "/*" and "*/" (non-nesting). The following code works, but is there a nice itertools combination or logical restructuring that would simplify it (and/or make it more "pythonic")?
def tokspan(starttok, endtok, stream):
inside = False
for tok in stream:
if (not inside) and tok == starttok:
inside = True
yield (inside, tok)
if inside and tok == endtok:
inside = False
tstream = "int x; /* a non-nesting comment /* etc. */ x=1; main();".split()
for status, tok in tokspan("/*", "*/", tstream):
print(status, tok)
The above (intentionally) returns True for the boundary tokens (/* and */), but that's not particularly important. If you have an approach that happens to exclude one or both boundaries (like python ranges do), I'd still like to know about it.
The only simplification that I can think of is rewriting the logic around setting/resetting inside:
def tokspan(starttok, endtok, stream):
inside = False
for tok in stream:
inside |= (tok == starttok)
yield (inside, tok)
inside &= (tok != endtok)
Whether this makes the code more or less readable is in the eye of the beholder.
It might be possible to use a decorator over here. I am not sure if this is going to be useful to you or not but this might just give you some ideas.
Create a decorator which stores the items you want to filter out with:
import itertools as it
class insideDec(object):
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __call__(self, f):
def wrapper(x):
x1 = it.dropwhile(lambda m: not m.startswith(self.start), x )
x1.next()
x2 = it.takewhile(lambda m: not m.startswith(self.stop), x1 )
return f(x2)
return wrapper
#insideDec('{', '}')
def f(val):
return val
if __name__ == '__main__':
print ''.join(f('This is some {string that needs to} be printed'))
Now you apply the decorator to a function that accepts a string. This will convert the function into one whose input is an iterator. You then process the iterator like you would any other iterator.
Of course, you can always convert the iterator to a string at any point of time (like for example over here):
# rest of the code ...
x2 = it.takewhile(lambda m: not m.startswith(self.stop), x1 )
return f(''.join(x2))
# rest of the code ...
That's really up to you ...
Edit:
Sorry about that. I misread your question. For tokenizing, maybe something like the following might help?
class tokenize():
def __init__(self, strVal, start, stop):
self.start = start
self.stop = stop
self.strTees = it.tee(strVal, len(start))
self.inside = False
for i, strTee in enumerate(self.strTees):
for j in range(i):
next(strTee, '')
self.strVals = it.izip( *self.strTees )
def __iter__(self):
return self
def next(self):
v = ''.join(self.strVals.next())
if v == '': raise StopIteration
if v == self.start: self.inside = True
if v == self.stop: self.inside = False
# print '[',v, ']'
return (v[0], self.inside)
if __name__ == '__main__':
strVal = 'int x; /* a non-nesting comment etc. */ x=1; main();'
for x, y in tokenize( strVal, '/*', '*/' ):
print x, y
Again, this is not perfect, by might serve your purposes ...
Here is the output:
i False
n False
t False
False
x False
; False
False
/ True
* True
True
a True
True
n True
o True
n True
- True
n True
e True
s True
t True
i True
n True
g True
True
c True
o True
m True
m True
e True
n True
t True
True
e True
t True
c True
. True
True
* False
/ False
False
x False
= False
1 False
; False
False
m False
a False
i False
n False
( False
) False
Related
I have a function, which checks given two node chains and determines whether those two node chains contain same data values in same order. Function returns True if they do and returns False otherwise. I need to write this function using recursion.
Here's my attempt:
def check_chains(chain1, chain2):
if chain1 is None or chain2 is None:
return False
else:
if chain1.get_data() == chain2.get_data():
check_chains(chain1.get_next(), chain2.get_next())
return True
else:
return False
This one returns True even if node chains have different data values in them.
Below are some test cases:
1. Test case 1 (test passed)
chain1 = N.node(5 ,N.node(10,N.node(-15, N.node(1))))
chain2 = N.node(5 ,N.node(10,N.node(-15, N.node(1))))
expected = True
result = a7q8.check_chains(chain1, chain2)
if result!=expected:
print('Test failed')
2. test 2 (test failed, expected false but returned True)
chain1 = N.node(5 ,N.node(10,N.node(-15, N.node(1))))
chain2 = N.node(5 ,N.node(10,N.node(7, N.node(1))))
expected = True
result = a7q8.check_chains(chain1, chain2)
if result!=expected:
print('Test failed')
Your logic was a little bit flawed in two places:
def check_chains(chain1, chain2):
# base case for equality was missing!
if chain1 is chain2 is None:
return True
if None in (chain1, chain2): # rewrote your condition less verbosely
return False
if chain1.get_data() == chain2.get_data():
# recursive result was never used!
return check_chains(chain1.get_next(), chain2.get_next())
return False
I also removed some spurious else, as you return from every if-block.
def check_chains(chain1, chain2):
if chain1 is None and chain2 is None:
return True
if chain1 is None or chain2 is None:
return False
else:
if chain1.get_data() == chain2.get_data():
return check_chains(chain1.get_next(), chain2.get_next())
else:
return False
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
I have a class for a Dialogue system as follows
class DIALOGUE(object):
def __init__(self, place, who, sTime, eTime, isActive, mood, menuText, func, repeatable, num):
self.place = place
self.who = who
self.sTime = sTime
self.eTime = eTime
self.isActive = isActive
self.mood = mood
self.menuText = menuText
self.func = func
self.repeatable = repeatable
self.num = num
#property
def ACheck(self):
global Date
if self.sTime == "none":
return True
else:
tHour,tMin = self.sTime.split(":")
if tHour >= Date.Hour and tMin <= Date.Minute:
tHour,tMin = self.eTime.split(":")
if tHour < Date.Hour and tMin < Date.Minute:
return True
return False
#property
def BCheck(self):
global Act
if self.who == Act:
return True
else:
return False
#property
def CCheck(self):
global Location
if self.place == Location:
return True
if self.place == "none":
return True
return False
#property
def DCheck(self):
if self.repeatable:
return True
else:
if self.num > 0:
return False
else:
return True
#property
def CanChat(self):
if self.isActive and self.ACheck and self.BCheck and self.CCheck and self.DCheck:
return True
else:
return False
def SetActive(self):
self.isActive = True
def Do(self):
self.num += 1
renpy.call(self.func)
Most of this should be self explanatory but I parse an XML file into a list of Instances of this class.
The user is presented with a list of available dialogues based on what Location they are in, what time of day it is and what NPC they have selected. If the dialogue is not repeatable The DCheck method looks at whether or not the dialogue has been completed before i.e if the dialogue is not repeatable and self.num > 0 the method will return False
Essentially it loops through all the dialogues and carries out i.CanChat and if this value returns True, the Dialogue is added to the menu
The issue I'm having is that the Check methods aren't returning the correct value. Specifically DCheck is returning True all the time, regardless of whether the Dialogue is repeatable or not, and ignoring the value of self.num
The class is created in an init python: block and then the xml file is parsed in a separate python block which is called from inside the start label
It's probably something really simple but I can't figure it out.
The list of instances is parsed as follows
Dialogues = []
for j in Dialo:
JPlace = j.find('Place').text
JWho = j.find('Who').text
JsTime = j.find('Start').text
JeTime = j.find('End').text
JMood = int(j.find('Mood').text)
JText = j.find('Text').text
JFunc = j.find('Func').text
JRep = j.find('Rep').text
if JRep == "True":
Jrep = True
else:
Jrep = False
Dialogues.append(DIALOGUE(JPlace, JWho, JsTime, JeTime, False, JMood, JText, JFunc, JRep, 0))
The method for creating the menu is as follows
def TalkCheck():
talks = []
talks.append(("Nevermind.", "none"))
for i, q in enumerate(Dialogues):
if q.CanChat:
talks.append((q.menuText,i))
renpy.say(None, "", interact=False)
talkchoice = renpy.display_menu(talks)
if talkchoice <> "none":
talkchoice = int(talkchoice)
Dialogues[talkchoice].Do()
Your question is incomplete - you didn't post a MCVE, we don't know the effective values for "repeatble" and "num" that leads to this behaviour, and we don't even know if it's using Python 2.x or Python 3.x - so we can just try and guess. Now since you mention that you "parse an XML file into a list of instances", I stronly suspect you are running Python 2.x and passing those values as strings instead of (resp.) boolean and int. In Python 2, "-1" (string) compares greater than 0 (int) - it raises a TypeError in Python 3.x -, and in both cases a non-empty string evals to True in a boolean context (bool('False') == True). Since there's no obvious logical error in your method implementation, that's the only explanation I can think of.
BTW, expressions have a boolean values and return exits the function, so you can simplify your code:
#property
def DCheck(self):
if self.repeatable:
return True
return self.num > 0
I have two functions that contain mostly the same code. One returns "True" if the array passed in contains all positive numbers while the other returns "True" if the array contains all numbers that are divisible by 10.
I want to combine these two functions into a function like this:
def master_function(array, function):
for i in array:
if function:
result = True
else:
result = False
break
print(result)
return result
The only part that would vary is the "function" in the If statement. When I write functions with the missing line they don't get called as the program executes.
def positive_integers(array):
i >= 0
def divisible_by_10(array):
i%10 == 0
The test code isn't executed either.
master_function([10,20,30,35],divisible_by_10)
Your functions aren't returning anything, and you need to give them access to i:
def positive_integers(i):
return i >= 0
def divisible_by_10(i):
return not i%10
def master_function(array, function):
for i in array:
if function(i):
result = True
else:
result = False
break
print(result)
return result
Your function don't return anything. Also, you need read about all and any:
def positive_integers(array):
return all(i >= 0 for i in array)
def divisible_by_10(array):
return all(i % 10 == 0 for i in array)
def master_function(array, function):
return function(array)
def master_function(array, function):
for i in array:
print str(i)
if function(i):
result = True
else:
result = False
print(result)
return result
def positive_integers(i):
if i >= 0:
return True
def divisible_by_10(i):
if i%10 == 0:
return True
master_function([10,20,30,35],divisible_by_10)
I am trying to write a Python 3 recursive function which will tell me if an integer is in a nested list. I am not sure how I can make my code return True if it finds it in the list, and False if it doesn't find it in the list. When I print the result of my for loop, I get a bunch of
false
false
false
false
true
false
false
false
etc. But, it returns False because the last call was false, even though I want it to return true. How can I fix this?
Here is my code:
def nestedListContains(NL, target):
if( isinstance(NL, int) ):
return NL
for i in range(0, len(NL)):
return ( nestedListContains(NL[i], target) == target )
return False
And here is how I'm calling it
print(nestedListContains([[3], [4,5,7], [[[8]]]], 8))
EDIT: This seems to be working for me, but it seems rather ghetto:
def nestedListContains(NL, target):
if( isinstance(NL, int) ):
if( NL == target ):
return 1
return 0
x = 0
for n in NL:
x += nestedListContains(n, target) == 1
return x != 0
My attempt:
def contains(lst, target):
if isinstance(lst, int):
return lst == target
return any(contains(x, target) for x in lst)
You return the result regardless of whether it's True or not. You could do something like this:
def nestedListContains(NL, target):
if isinstance(NL, int):
return NL == target
for n in NL:
result = nestedListContains(n, target)
if result:
return result
return False
Using duck typing for #gatto's solution
def contains(lst, target):
try:
return any(contains(x, target) for x in lst)
except TypeError:
return lst == target