restart the class with initial argument value python - python

I am trying to do a class to manipulate a nested list ,
a_list = [ a, b, c, d, e, f, g] will be an initial argument , then I will have some other methods to manipulate the list. However, I will need to keep a copy of the original list, that by anytime I can restart it to the initial stage by calling the restart() method ,
i tried a couple of times but it didn't work, can anyone give me a hand?
class Sample:
def __init__(self, a_list, count):
self.__a_list = a_list
self.__count = 0
self.__reset_list = a_list.copy()
def restart(self):
self.__a_list = self.__reset_list
return
This is a full test case, it did not get back to the original value:
class Sample:
def __init__(self, a_list, count=0):
self.__a_list = a_list
self.__count = 0
self.__reset_list = a_list.copy()
def set_update(self):
self.__a_list[2][2] = "S"
def restart(self):
self.__a_list = self.__reset_list
return
def __str__(self):
result_list = self.__a_list
result = ''
for i in range(len(result_list)):
for j in range(len(result_list[i])):
result += result_list[i][j] + ' '
if i < len(result_list) -1:
result += '\n'
return result
test = [
['*', '*', '*', '*', '*', '*', '*', '*'],
['*', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
['*', ' ', ' ', '#', 'P', ' ', ' ', '*'],
['*', '*', '*', '*', '*', ' ', '#', '*'],
['*', 'o', ' ', ' ', ' ', ' ', ' ', '*'],
['*', ' ', ' ', ' ', ' ', ' ', 'o', '*'],
['*', '*', '*', ' ', '*', '*', '*', '*']
]
a_case = Sample(test)
print(a_case)
a_case.set_update()
print(a_case)
a_case.restart()
print(a_case)

You need to copy the list on restart:
def restart(self):
self.__a_list = self.__reset_list.copy()
Otherwise __a_list points to the same list as __reset_list, and the latter will reflect any modifications made to __a_list

One thing i noticed was, this issue is not happening in 1D array. as a solution you can use deepcopy. check the answer below.
import copy
class Sample:
def __init__(self, a_list, count=0):
self.__a_list = a_list
self.__count = 0
self.__reset_list = copy.deepcopy(a_list) #use deepcopy to copy the array

Finally, I found a solution by using the nested list to nested tuple conversion
using tuples
class Sample:
def __init__(self, a_list, count=0):
self.__a_list = a_list
self.__count = 0
self.__reset_list = a_list.copy()
self.__tracks = []
def set_update(self,i,j):
current_copy = tuple(tuple(i) for i in self.__a_list)
self.__tracks.append(current_copy)
self.__a_list[i][j] = "S"
def restart(self):
initial_copy = [list(i) for i in self.__tracks[0]]
self.__a_list = initial_copy
while len(self.__tracks) > 0:
self.__tracks.pop()
return self.__a_list
def undo(self):
self.__tracks.pop()
last_copy = [list(i) for i in self.__tracks[-1]]
print(last_copy)
self.__a_list = last_copy
self.__tracks.pop()
return self.__a_list
def __str__(self):
result_list = self.__a_list
result = ''
for i in range(len(result_list)):
for j in range(len(result_list[i])):
result += result_list[i][j] + ' '
if i < len(result_list) -1:
result += '\n'
return result
test = [
['*', '*', '*', '*', '*', '*', '*', '*'],
['*', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
['*', ' ', ' ', '#', 'P', ' ', ' ', '*'],
['*', '*', '*', '*', '*', ' ', '#', '*'],
['*', 'o', ' ', ' ', ' ', ' ', ' ', '*'],
['*', ' ', ' ', ' ', ' ', ' ', 'o', '*'],
['*', '*', '*', ' ', '*', '*', '*', '*']
]
a_case = Sample(test)
print(a_case)
a_case.set_update(2,2)
print(a_case)
a_case.set_update(2,3)
print(a_case)
a_case.set_update(3,3)
print(a_case)
a_case.undo()
print(a_case)
a_case.restart()
print(a_case)

Related

Transform a code tokens list into valid string code

I have written code to transform Python code into a list to compute BLEU score:
import re
def tokenize_for_bleu_eval(code):
code = re.sub(r'([^A-Za-z0-9_])', r' \1 ', code)
code = re.sub(r'([a-z])([A-Z])', r'\1 \2', code)
code = re.sub(r'\s+', ' ', code)
code = code.replace('"', '`')
code = code.replace('\'', '`')
tokens = [t for t in code.split(' ') if t]
return tokens
Thanks to this snippet my code struct.unpack('h', pS[0:2]) is parsed properly into the list ['struct', '.', 'unpack', '(', 'h', ',', 'p', 'S', '[', '0', ':', '2', ']', ')'].
Initially, I thought I need simply to use the ' '.join(list_of_tokens) but it kills my variable names like this struct . unpack ('h' , p S [ 0 : 2 ] ) and my code is not executable.
I tried to use Regex to stick some variable names but I can't succeed to reverse my function tokenize_for_bleu_eval to find executable code at the end. Is someone get an idea, perhaps without regex which seems to be too complicated here?
EDIT: We can't just remove all spaces between element of the list because there are examples like items = [item for item in container if item.attribute == value] where the result of the backtranslation without space would be itemforiteminaifitem[0]==1 which is not valid.
I am trying to merge the tokens using this script
import re
def tokenize_for_bleu_eval(code):
code = re.sub(r'([^A-Za-z0-9_])', r' \1 ', code)
code = re.sub(r'([a-z])([A-Z])', r'\1 \2', code)
code = re.sub(r'\s+', ' ', code)
code = code.replace('"', '`')
code = code.replace('\'', '`')
tokens = [t for t in code.split(' ') if t]
return tokens
def merge_tokens(tokens):
code = ''.join(tokens)
code = code.replace('`', "'")
code = code.replace(',', ", ")
return code
tokenize = tokenize_for_bleu_eval("struct.unpack('h', pS[0:2])")
print(tokenize) # ['struct', '.', 'unpack', '(', '`', 'h', '`', ',', 'p', 'S', '[', '0', ':', '2', ']', ')']
merge_result = merge_tokens(tokenize)
print(merge_result) # struct.unpack('h', pS[0:2])
Edit:
I found this interesting idea to tokenize and merge.
import re
def tokenize_for_bleu_eval(code):
tokens_list = []
codes = code.split(' ')
for i in range(len(codes)):
code = codes[i]
code = re.sub(r'([^A-Za-z0-9_])', r' \1 ', code)
code = re.sub(r'([a-z])([A-Z])', r'\1 \2', code)
code = re.sub(r'\s+', ' ', code)
code = code.replace('"', '`')
code = code.replace('\'', '`')
tokens = [t for t in code.split(' ') if t]
tokens_list.append(tokens)
if i != len(codes) -1:
tokens_list.append([' '])
flatten_list = []
for tokens in tokens_list:
for token in tokens:
flatten_list.append(token)
return flatten_list
def merge_tokens(flatten_list):
code = ''.join(flatten_list)
code = code.replace('`', "'")
return code
test1 ="struct.unpack('h', pS[0:2])"
test2 = "items = [item for item in container if item.attribute == value]"
tokenize = tokenize_for_bleu_eval(test1)
print(tokenize) # ['struct', '.', 'unpack', '(', '`', 'h', '`', ',', ' ', 'p', 'S', '[', '0', ':', '2', ']', ')']
merge_result = merge_tokens(tokenize)
print(merge_result) # struct.unpack('h', pS[0:2])
tokenize = tokenize_for_bleu_eval(test2)
print(tokenize) # ['items', ' ', '=', ' ', '[', 'item', ' ', 'for', ' ', 'item', ' ', 'in', ' ', 'container', ' ', 'if', ' ', 'item', '.', 'attribute', ' ', '=', '=', ' ', 'value', ']']
merge_result = merge_tokens(tokenize)
print(merge_result) # items = [item for item in container if item.attribute == value]
This script will also remember each space from the input

How do I swap the rows and different values in my function?

I am currently in a coding class and I am trying to learn Python (Python 3) and I have written some code here for an assignment but I am apparently getting the swapping wrong and I don't know how to fix it. I have the assignment's instructions and I also have a comment on my code that I need help understanding. Can someone please show me how to flip the rows by swapping the different values?
Here are the instructions:
Here is my code:
def flipIt(array):
for i in range(len(array)):
length = len(array[i])
for j in range(length // 2):
temp = array[i][j]
array[i][j] = array[i][length - 1 - j]
array[i][length - 1 - j] = temp
pic = [['#', ' ', ' ', ' ', ' ', '#'],
['#', '#', ' ', ' ', ' ', '#'],
['#', ' ', '#', ' ', ' ', '#'],
['#', ' ', ' ', '#', ' ', '#'],
['#', ' ', ' ', ' ', '#', '#'],
['#', ' ', ' ', ' ', ' ', '#']]
flipIt(pic)
for i in pic:
for j in i:
print(j,end=' ')
print()
Here is the comment:
How do I do what the comment says?
Mmh, it took me some time to realize the problem because flipping this picture vertically and horizontally gives the same result. In your case, what you want to do is:
def flipIt(array):
height = len(array)
for i in range(len(array) // 2):
temp = array[i]
array[i] = array[height-1-i]
array[height-1-i] = temp
# No need for return because it is modified in place
pic = [['#', ' ', ' ', ' ', ' ', '#'],
['#', '#', ' ', ' ', ' ', '#'],
['#', ' ', '#', ' ', ' ', '#'],
['#', ' ', ' ', '#', ' ', '#'],
['#', ' ', ' ', ' ', '#', '#'],
['#', ' ', ' ', ' ', ' ', '#']]
flipIt(pic)
for i in pic:
for j in i:
print(j,end=' ')
print()
Of course, as Sam Stafford suggested, you can make it even simpler (given that you are allowed) with
def flipIt(array):
array.reverse()
The flipIt function is unneeded since Python has a built-in way to do this. All you need to do is replace:
flipIt(pic)
with:
pic.reverse()
(You could also do something like flipIt = lambda img: img.reverse() if you wanted an extra layer of abstraction in there, or because the assignment required you to have a function that was specifically called flipIt.)
The list.reverse() method operates on any list and does an in-place reversal of its elements. Since pic is a list of rows in the image, reversing the order has the effect of flipping it vertically.
You can also simplify your print loop by using str.join() to turn each row into a single string.
>>> pic = [['#', ' ', ' ', ' ', ' ', '#'],
... ['#', '#', ' ', ' ', ' ', '#'],
... ['#', ' ', '#', ' ', ' ', '#'],
... ['#', ' ', ' ', '#', ' ', '#'],
... ['#', ' ', ' ', ' ', '#', '#'],
... ['#', ' ', ' ', ' ', ' ', '#']]
>>> pic.reverse() # flip the rows from top to bottom
>>> for row in pic:
... print(' '.join(row))
...
# #
# # #
# # #
# # #
# # #
# #
Your current code actually works just fine. You just forgot to return your flipped array from your function:
def flipit(array):
for i in range(len(array)):
length = len(array[i])
for j in range(length // 2):
temp = array[i][j]
array[i][j] = array[i][length - 1 - j]
array[i][length -1 -j] = temp
return array
pic = [['#', ' ', ' ', ' ', ' ', '#'],
['#', '#', ' ', ' ', ' ', '#'],
['#', ' ', '#', ' ', ' ', '#'],
['#', ' ', ' ', '#', ' ', '#'],
['#', ' ', ' ', ' ', '#', '#'],
['#', ' ', ' ', ' ', ' ', '#']
]
x = flipit(pic)
print(x)

Why element does not replace in numpy.array?

I want to assign a new value to [i + 1][j] of array, but it seems there is a problem.
a = np.array(['#', '#', '#', '#', '#', '#','#', ' ', ' ', 'A', ' ', '#',
'#', ' ', '#', 'P', ' ', '#',
'#', ' ', ' ', ' ', ' ', '#',
'#', 'P', ' ', ' ', ' ', '#',
'#', '2', ' ', ' ', ' ', '#',
'#', '#', '#', '#', '#', '#'])
print(len(a))
b = np.reshape(a,(7,6))
i = 0
j = 0
print(b[i + 1][j])
b[i + 1][j] = 'AP'
print(b[i + 1][j])
output:
#
A
How can I assign "AP" instead of "#" ?
b.dtype (see data type objects) is <U1 which is a unicode string of length 1.
you could fix that with
a = np.array(['#',..., '#'], dtype='<U2')
which will then accept strings up to length 2.

Issue using regex to split strings with a list of delimiters

I am using this function to split a text in words and separators while preserving them
import re
def split_text_in_words(phrase_text, separators=[" "]):
separator_regex = """({0})""".format("""|""".join(separators))
return [f for f in re.split(separator_regex,phrase_text) if len(f) > 0]
I am using this code like this:
>>> split_text_in_words('Mary & his family has a?nice.house at #157, at the beach? Of course! it is great. I owe her 40$ so I plan to pay my debt weekly at 3% interest :) "no comment"', separators=[' ', '\?', '\*', '\.', ',', ';', ':', "'", '"', '-', '\?', '!', '#', '\$', '%', '^', '&'])
['Mary', ' ', '&', ' ', 'his', ' ', 'family', ' ', 'has', ' ', 'a', '?', 'nice', '.', 'house', ' ', 'at', ' ', '#', '157', ',', ' ', 'at', ' ', 'the', ' ', 'beach', '?', ' ', 'Of', ' ', 'course', '!', ' ', 'it', ' ', 'is', ' ', 'great', '.', ' ', 'I', ' ', 'owe', ' ', 'her', ' ', '40', '$', ' ', 'so', ' ', 'I', ' ', 'plan', ' ', 'to', ' ', 'pay', ' ', 'my', ' ', 'debt', ' ', 'weekly', ' ', 'at', ' ', '3', '%', ' ', 'interest', ' ', ':', ')', ' ', '"', 'no', ' ', 'comment', '"']
This looks good so far and is precisely what I want. However when adding parens on the list of separators and I happen to have the text starting with a parens, the splitting gears don't kick in:
>>> split_text_in_words('(as if it was not aware) Mary & his family has a?nice beach* house at #157, at the beach? Of course! it is great. I owe her 40$ so I plan to pay my debt weekly at 3% interest :) "no comment"', separators=[' ', '\?', '\*', '\.', ',', ';', ':', "'", '"', '-', '\?', '!', '#', '\$', '%', '^', '&', '\*', '\(', '\)'])
['(as', ' ', 'if', ' ', 'it', ' ', 'was', ' ', 'not', ' ', 'aware', ')', ' ', 'Mary', ' ', '&', ' ', 'his', ' ', 'family', ' ', 'has', ' ', 'a', '?', 'nice', ' ', 'beach', '*', ' ', 'house', ' ', 'at', ' ', '#', '157', ',', ' ', 'at', ' ', 'the', ' ', 'beach', '?', ' ', 'Of', ' ', 'course', '!', ' ', 'it', ' ', 'is', ' ', 'great', '.', ' ', 'I', ' ', 'owe', ' ', 'her', ' ', '40', '$', ' ', 'so', ' ', 'I', ' ', 'plan', ' ', 'to', ' ', 'pay', ' ', 'my', ' ', 'debt', ' ', 'weekly', ' ', 'at', ' ', '3', '%', ' ', 'interest', ' ', ':', ')', ' ', '"', 'no', ' ', 'comment', '"']
The first parens remains attached to the word. I can work around this issue by simply appending a space at beginning:
>>> split_text_in_words(' (as if it was not aware) Mary & his family has a?nice beach* house at #157, at the beach? Of course! it is great. I owe her 40$ so I plan to pay my debt weekly at 3% interest :) "no comment"', separators=[' ', '\?', '\*', '\.', ',', ';', ':', "'", '"', '-', '\?', '!', '#', '\$', '%', '^', '&', '\*', '\(', '\)'])
[' ', '(', 'as', ' ', 'if', ' ', 'it', ' ', 'was', ' ', 'not', ' ', 'aware', ')', ' ', 'Mary', ' ', '&', ' ', 'his', ' ', 'family', ' ', 'has', ' ', 'a', '?', 'nice', ' ', 'beach', '*', ' ', 'house', ' ', 'at', ' ', '#', '157', ',', ' ', 'at', ' ', 'the', ' ', 'beach', '?', ' ', 'Of', ' ', 'course', '!', ' ', 'it', ' ', 'is', ' ', 'great', '.', ' ', 'I', ' ', 'owe', ' ', 'her', ' ', '40', '$', ' ', 'so', ' ', 'I', ' ', 'plan', ' ', 'to', ' ', 'pay', ' ', 'my', ' ', 'debt', ' ', 'weekly', ' ', 'at', ' ', '3', '%', ' ', 'interest', ' ', ':', ')', ' ', '"', 'no', ' ', 'comment', '"']
But I'm concerned why this happening and if the strategy (hack, really) of adding a space at the beginning does not reassure me that it won't fail in some other more subtle case
Why is this happening, and would the hack/fix of appending a space at the beginning work in general?
The problem is the unescaped ^. You should probably escape all punctuation characters you use with something like:
split_text_in_words(
'(as if it was not aware) Mary & his family',
separators=["\\" + c for c in " ?*.,;:'\"-!#$%^&()"]
)
Maybe, even do it in the function:
import re
def split_text_in_words(phrase_text, separators=[" "]):
inter = "|".join(
re.sub(r"(^|[^\\])([^A-Za-z0-9])", r"\\\2", sep) for sep in separators
)
# Add the backslash if not already present for every non-alphanumeric
# character.
separator_regex = "({0})".format(inter)
return [f for f in re.split(separator_regex, phrase_text) if len(f) > 0]
Problem is use of unescaped ^ in your separator that becomes part of your splitting regex. ^ is a special regex meta-character that means start anchor.
You must escape it as this:
separators=[' ', '\?', '\*', '\.', ',', ';', ':', "'", '"', '-', '\?', '!', '#', '\$', '%', '\^', '&', '\*', '\(', '\)']
^ marks the beginning of the string so it must be escaped in the separator list: '\^'
A more comfortable and safer way would be to not escape the separators in the parameter but in the function instead:
separator_regex = """({0})""".format("""|""".join(map(re.escape, separators)))

Partitioning a string in Python by a regular expression

I need to split a string into an array on word boundaries (whitespace) while maintaining the whitespace.
For example:
'this is a\nsentence'
Would become
['this', ' ', 'is', ' ', 'a' '\n', 'sentence']
I know about str.partition and re.split, but neither of them quite do what I want and there is no re.partition.
How should I partition strings on whitespace in Python with reasonable efficiency?
Try this:
s = "this is a\nsentence"
re.split(r'(\W+)', s) # Notice parentheses and a plus sign.
Result would be:
['this', ' ', 'is', ' ', 'a', '\n', 'sentence']
Symbol of whitespace in re is '\s' not '\W'
Compare:
import re
s = "With a sign # written # the beginning , that's a\nsentence,"\
'\nno more an instruction!,\tyou know ?? "Cases" & and surprises:'\
"that will 'lways unknown **before**, in 81% of time$"
a = re.split('(\W+)', s)
print a
print len(a)
print
b = re.split('(\s+)', s)
print b
print len(b)
produces
['With', ' ', 'a', ' ', 'sign', ' # ', 'written', ' # ', 'the', ' ', 'beginning', ' , ', 'that', "'", 's', ' ', 'a', '\n', 'sentence', ',\n', 'no', ' ', 'more', ' ', 'an', ' ', 'instruction', '!,\t', 'you', ' ', 'know', ' ?? "', 'Cases', '" & ', 'and', ' ', 'surprises', ':', 'that', ' ', 'will', " '", 'lways', ' ', 'unknown', ' **', 'before', '**, ', 'in', ' ', '81', '% ', 'of', ' ', 'time', '$', '']
57
['With', ' ', 'a', ' ', 'sign', ' ', '#', ' ', 'written', ' ', '#', ' ', 'the', ' ', 'beginning', ' ', ',', ' ', "that's", ' ', 'a', '\n', 'sentence,', '\n', 'no', ' ', 'more', ' ', 'an', ' ', 'instruction!,', '\t', 'you', ' ', 'know', ' ', '??', ' ', '"Cases"', ' ', '&', ' ', 'and', ' ', 'surprises:that', ' ', 'will', ' ', "'lways", ' ', 'unknown', ' ', '**before**,', ' ', 'in', ' ', '81%', ' ', 'of', ' ', 'time$']
61
Try this:
re.split('(\W+)','this is a\nsentence')

Categories

Resources