Class method changing variable - python

I am kind of new to python and I am facing a lot of trouble because for some reason this value within my class method is updating by it self even though I didn't touch it. I can't even make it constant... Here is the relevant piece of code that does it.
the method that is called:
def swapping(self,pos,puzzle):
print('Old puzzle \n',puzzle)
# Getting Zero point index
zero = obj.null_pos(puzzle)
# Getting Index of varied position
var = puzzle[pos[0]][pos[1]]
#Swappping values
puzzle[zero[0,0],zero[0,1]] = var
puzzle[pos[0], pos[1]] = 0
new_puzzle = puzzle
print('New_puzzle \n',new_puzzle)
return new_puzzle
# The code has been snipped into relevant parts only
for i in range(len(child_node)):
# Check the hn of each node
print(child_node[i])
#where it occurs:
num_mispl = obj.misplaced_tiles(nod.swapping(child_node[i],new_puz))
# <-- new_puz #value changes and i didn't assign it to anything
temp_stor.append(num_mispl)

Related

How do I access the parameters of the function one by one?

So, I'm still learning how to code and I'm making this higher or lower game, and I made a function that pulls out info from a huge list with dictionaries inside it called "data":
Here is my code so far:
def choice_of_oponents(opponent1, opponent2):
"""
Gets the info on 2 people randomly and assigns them to the variables 'opponent1' and 'opponent2'
"""
opponent1 = random.choice(data)
opponent2 = random.choice(data)
def winner(opponent1, opponent2):
#This function is supposed to pull out the info stored in the parameters in the first function and determine the winner based on the data
I'm not sure how to write the second function or if it is even possible to pull out info from the parameters of the 1st function without making extra variables. Can someone help solve this?
Maybe what you're missing is the concept of return-ing the output of a function. Also, you don't need any inputs to your first function (note that you didn't use them anyway).
Try something like this:
def choice_of_opponents():
"""
Gets the info on 2 people randomly and assigns them to the variables
'opponent1' and 'opponent2'
"""
opponent1_result = random.choice(data)
opponent2_result = random.choice(data)
return opponent1_result, opponent2_result
def winner(opponent1, opponent2):
if opponent1 > opponent2:
return 1
elif opponent2 > opponent1:
return 2
else:
return 0 # A tie
op1, op2 = choice_of_opponents()
print(winner(op1, op2))

Updating local variable within function not working correctly [duplicate]

This question already has answers here:
Static variable in Python?
(6 answers)
Closed 1 year ago.
I'm trying to write a function that updates its local variable each time it is run but it is not working for some reason.
def max_equity(max_equity=0):
if current_equity() > max_equity:
max_equity = current_equity()
print(max_equity)
return max_equity
else:
print(max_equity)
return max_equity
and the function which it is calling
def current_equity():
for n in range(len(trade_ID_tracker)-1):
equity_container = 0
if (trade_ID_tracker[n,2]) == 0:
break
else:
if (trade_ID_tracker[n, 1].astype(int) == long):
equity_container += (df.loc[tbar_count,'Ask_Price'] - trade_ID_tracker[n, 2]) * trade_lots * pip_value * 1000
elif (trade_ID_tracker[n, 1].astype(int) == short):
equity_container += 0 - (df.loc[tbar_count,'Ask_Price'] - trade_ID_tracker[n, 2]) * trade_lots * pip_value * 10000
return (current_balance + equity_container)
but for some reason the max_equity() function prints current_equity() which I can only imagine means that either:
if current_equity() > max_equity:
is not doing it's job and is triggering falsely
or
max_equity = current_equity()
is not doing its job and max_equity starts at zero every time it is run.
In other words if I put max_equity() in a loop where current_equity() is
[1,2,3,4,5,4,3,2,1]
then max_equity() should return
[1,2,3,4,5,5,5,5,5]
But instead it returns
[1,2,3,4,5,4,3,2,1]
Here's a quick example test
ar = [1,2,3,4,5,4,3,2,1]
def stuff(max_equity=0):
if ar[n] > max_equity:
max_equity = ar[n]
print(max_equity)
else:
print(max_equity)
for n in range(len(ar)):
stuff()
Either way I'm kind of stumped.
Any advice?
local function variables are reset at each function call. This is essential for the behavior of functions as idempotent, and is a major factor in the success of the procedural programming approach: a function can be called form multiple contexts, and even in parallel, in concurrent threads, and it will yield the same result.
A big exception, and most often regarded as one of the bigger beginner traps of Python is that, as parameters are reset to the default values specified in the function definition for each call, if these values are mutable objects, each new call will see the same object, as it has been modified by previous calls.
This means it could be done on purpose by, instead of setting your default value as 0 you would set it as a list which first element was a 0. At each run, you could update that value, and this change would be visible in subsequent calls.
This approach would work, but it is not "nice" to depend on a side-effect of the language in this way. The official (and nice) way to keep state across multiple calls in Python is to use objects rather than functions.
Objects can have attributes tied to them, which are both visible and writable by its methods - which otherwise have their own local variables which are re-started at each call:
class MaxEquity:
def __init__(self):
self.value = 0
def update(max_equity=0):
current = current_equity()
if current > self.value:
self.value = current
return self.value
# the remainder of the code should simply create a single instance
# of that like ]
max_equity = MaxEquity()
# and eeach time yoiu want the max value, you should call its "update"
# method

ArcGIS Field Calculator: Conditional statement syntax error

Rudimentary Python/ArcPy skills at work here, not sure where I'm going wrong.
Trying to do a simple random selection of 10 features from a layer to be indicated by the placement of a "1" in another attribute set aside for this purpose. Basic concept is is to use random.sample() to generate a random list of 10 FID's, and then check to see if each FID is in the list. NewID is an attribute containing FID's values. This is what I have in the code block:
import random
def randSelTen():
featurecount = arcpy.GetCount_management("layer_name")
linecount = int(str(featurecount))
lst_oids = range(0, linecount)
rand_lines = random.sample(lst_oids, 10)
if !NewID! in rand_lines:
return 1
else:
return 0
I keep getting a syntax error on the conditional containing !NewID!, and no matter what I do I can't fix it. If I replace !NewID! with an integer, the script runs, but of course the output is bad. Any help is appreciated... thanks!
If you are putting this code in the "Codeblock" of the field calculator then the reason you are getting a syntax error is because you can not access fields like that from the codeblock. You must pass in the field as an argument to the function. So you would have to do this:
# -----Codeblock---------
import random
def randSelTen(NewID):
featurecount = arcpy.GetCount_management("layer_name")
linecount = int(str(featurecount))
lst_oids = range(0, linecount)
rand_lines = random.sample(lst_oids, 10)
if NewID in rand_lines:
return 1
else:
return 0
# ----- Expression (goes in bottom text box of the field calculator if using GUI) -----
randSelTen(!NewID!)

Checking that array doesn't contain negative numbers, and running function again if it does

My task today is to create a way for checking if a function's output contains negative numbers, and if it does, then I must run the function until it contains no negative numbers.
I'll post the full code later in the post, but this is my attempt at a solution:
def evecs(matrixTranspose):
evectors = numpy.linalg.eig(matrixTranspose)[1][:,0]
return evectors
if any(x<0 for x in evectors) == False:
print(evectors)
evecs() is my function, and evectors is the output array, but I only want to print evectors if there are no negative entries in it. I also want to later add that if there are negative entries in it, the code should run the evecs function again until it finds an evectors that has no negative entries.
However, whenever I run it I get the error:
global name evectors is not defined
Here's a link to my code, and the full output from the iPython console. http://pastebin.com/3Bk9h1gq
Thanks!
You have not declared the variable evectors other than within the scope of your function evecs.
evectors = evecs(matrixTranspose)
if any(x<0 for x in evectors) == False:
print(evectors)
EDIT
There are several issues:
Indentation is VERY important in Python. MarkovChain and evecs are two seperate functions. You had your evacs function indented an extra level in, embeddeding it within MarkovChain.
MarkovChain should return matrixTransponse if you plan to use it in another function call.
As a result of the above issue, your function call to MarkovChain needs to be assigned to a variable, matrixTranponse, otherwise you will get an error stating that matrixTranspose is not defined when you make your function call to evecs with it.
Since the initialization of the variable matrixTranspose isn't set until the function call to MarkovChain is completed, the remainder of your logic will need to be re-ordered.
I have applied all the above changes below and added comments to the changed areas:
def MarkovChain(n,s) :
"""
"""
matrix = []
for l in range(n) :
lineLst = []
sum = 0
crtPrec = precision
for i in range(n-1) :
val = random.randrange(crtPrec)
sum += val
lineLst.append(float(val)/precision)
crtPrec -= val
lineLst.append(float(precision - sum)/precision)
matrix2 = matrix.append(lineLst)
print("The intial probability matrix.")
print(tabulate(matrix))
matrix_n = numpy.linalg.matrix_power(matrix, s)
print("The final probability matrix.")
print(tabulate(matrix_n))
matrixTranspose = zip(*matrix_n)
return matrixTransponse # issue 2
# issue 1
def evecs(matrixTranspose):
evectors = numpy.linalg.eig(matrixTranspose)[1][:,0]
return evectors
matrixTranponse = MarkovChain(4, 10000000000) # issue 3
# issue 4
evectors = evecs(matrixTranspose)
if any(x<0 for x in evectors) == False:
print(evectors)

List index out of range - python array error

File "C:\Users\Tom\Desktop\Tetris!\tetris.py", line 206, in typeSet
Globals.blockArray[i].x.append(7)
IndexError: list index out of range
I get the above error for the 4th line in typeSet
At initialization:
def main():
initialize()
def initialize():
Globals.running = True
addBlock()
class Globals:
running = True
blockArray = []
blockNum = 0
And then later on:
def addBlock():
Globals.blockArray.append(block())
class block:
def __init__(self):
self.id = Globals.blockNum
Globals.blockNum += 1
self.x = []
self.y = []
self.landed = False
self.blockType = 1#random.randint(1,6)
self.typeSet()
def typeSet(self):
i = self.id
if self.blockType == 1:
#square(i)
Globals.blockArray[i].x.append(7)
Globals.blockArray[i].y.append(0)
Globals.blockArray[i].x.append(7)
Globals.blockArray[i].y.append(1)
Globals.blockArray[i].x.append(8)
Globals.blockArray[i].y.append(0)
Globals.blockArray[i].x.append(8)
Globals.blockArray[i].y.append(1)
Edit: added more code and switched it so the id should start at 0. Error code hasn't changed
Not enough code. The error tells you the exact problem. Globals.blockArray does not have a member at position i. That's why you shouldn't work with global variables when you can avoid them, since it can be a hard time making sure your global variables have the expected values in them.
I'm not sure but maybe you want to do
Globals.blockArray.append(self)
in the init function, and also increase Globals.blockNum after the assignment to self.id.
Every time an instance of block is created, Globals.blockNum is incremented by 1 and self.id is set to the current value of Globals.blockNum.
Later (in typeSet) self.id is used to index into Globals.blockArray.
The error occurs when Globals.blockArray doesn't have at least self.id + 1 items in it.
If Globals.blockNum keeps increasing and its value is used (indirectly) to index into Globals.blockArray, this will likely cause the error (unless something causes Globals.blockArray to keep growing too.
While nothing immediate comes to mind looking at your code above, the first thing I would try would be to print the contents of Globals.blockArray, and Globals.blockArray[i].

Categories