I'm writing some code to create a toolbar that edits a map in ArcMap and I'm having some issues with getting variable values from other functions inside other classes that I'm using.
All the functions are predefined so I can't change the int arguments or the code will throw an error. I checked the dir() and none of the variables I define using self are in the functions. I don't think I've made a syntax error and the code inside the other classes works correctly.
Here is my code:
import arcpy
import math
import pythonaddins
class findingCoordinates(object):
"""Implementation for leetScripts_addin.tool (Tool)"""
def __init__(self):
self.enabled = True
self.shape = "NONE"
def onMouseDownMap(self, x, y, button, shift):
print "onMouseDowMap executing"
#this is where I declared the first two variables using self
self.x = x
self.y = y
print "Selected point is at %r, %r" % (self.x, self.y)
pass
class squareFeetInput(object):
"""Implementation for leetScripts_addin.combobox (ComboBox)"""
def __init__(self):
self.editable = True
self.enabled = True
#self.dropdownWidth = 'WWWWWW'
self.width = 'WWWWWW'
def onEditChange(self, text):
squareFeet = text
#this is the other variable I defined that I need to use later
self.buffDist = (math.sqrt(float(squareFeet))/2)
print "Square size: %r ft^2 Buffer Distance: %r ft^2" % (squareFeet,self.buffDist)
print "self.buffdist is a %r type" % self.buffDist
return self.buffDist
pass
class buildingTool(object):
"""Implementation for leetScripts_addin.button (Button)"""
def __init__(self):
self.enabled = True
self.checked = False
def onClick(self):
print "building tool is executing"
#shows im_self, but no x or y
print "%r" % dir(findingCoordinates.onMouseDownMap)
# Get arguments:
# Input point feature class
# Output polygon feature class
# Buffer distance
# Boolean type: Maintain fields and field values of the input in the output
#This is where the problem is. I can't get these values from the previous functions.
inPoints = (findingCoordinates.onMouseDownMap.x,findingCoordinates.onMouseDownMap.y)
outPolys = "U:\JackBuildingFootprints.gdb\BuildingFootprintsCopy"
bufDist = squareFeetInput.buffDist
keepFields = true
# Prepare the output based on whether field and field values are desired in the output
#
if keepFields:
# Create empty output polygon feature class that includes fields of the input
#
arcpy.CreateFeatureClass(os.path.dirname(outPolys), os.path.basename(outPolys), "POLYGON",
inPoints, "", "", inPoints)
# Create a short list of fields to ignore when moving fields values from
# input to output
#
ignoreFields = []
# Use Describe properties to identify the shapeFieldName and OIDFieldName
#
desc = arcpy.Describe(inPoints)
ignoreFields.append(desc.shapeFieldName)
ignoreFields.append(desc.OIDFieldName)
# Create a list of fields to use when moving field values from input to output
#
fields = arcpy.ListFields(inPoints)
fieldList = []
for field in fields:
if field.name not in ignoreFields:
fieldList.append(field.name)
else:
# Create empty output polygon feature class without fields of the input
#
arcpy.CreateFeatureclass(os.path.dirname(outPolys), os.path.basename(outPolys), "POLYGON",
"", "", "", inPoints)
# Open searchcursor
#
inRows = arcpy.SearchCursor(inPoints)
# Open insertcursor
#
outRows = arcpy.InsertCursor(outPolys)
# Create point and array objects
#
pntObj = arcpy.Point()
arrayObj = arcpy.Array()
for inRow in inRows: # One output feature for each input point feature
inShape = inRow.shape
pnt = inShape.getPart(0)
# Need 5 vertices for square buffer: upper right, upper left, lower left,
# lower right, upper right. Add and subtract distance from coordinates of
# input point as appropriate.
for vertex in [0,1,2,3,4]:
pntObj.ID = vertex
if vertex in [0,3,4]:
pntObj.X = pnt.X + bufDist
else:
pntObj.X = pnt.X - bufDist
if vertex in [0,1,5]:
pntObj.Y = pnt.Y + bufDist
else:
pntObj.Y = pnt.Y - bufDist
arrayObj.add(pntObj)
# Create new row for output feature
#
feat = outRows.newRow()
# Shift attributes from input to output
#
if keepFields == "true":
for fieldName in fieldList:
feat.setValue(fieldName, inRow.getValue(fieldName))
# Assign array of points to output feature
#
feat.shape = arrayObj
# Insert the feature
#
outRows.insertRow(feat)
# Clear array of points
#
arrayObj.removeAll()
# Delete inputcursor
#
del outRows
pass
What am I doing wrong? Is this one of the rare occasions where I should use a global variable? Why is the directory not showing the variables I defined using self?
Edit:
I made this post a while ago and I just wanted to clear some things up now that I know more.
First:
This is code that is designed to be use with python_add_in. Python add in creates a toolbar based on some parameters you give it when you set it up, and whatever python code you put into a template it makes as a result of those parameters. That essentially means that all of the classes in the script above are events that occur when buttons and other toolbar objects are clicked or used in the toolbar.
Second:
The solution to this problem actually isn't in the accepted answer, my bad.
The root cause of the problem is that I was using class names that I declared in my script, findingCoordinates for example. python_add_in doesn't recognize these class names as the names of the classes it expects to receive based on the template you fill out before you start coding.
With that in mind, the issue was that I was trying to call classes that just didn't exist as far as python_add_in was concerned. The solution is to just go ahead and use the class names python_add_in tool expects you to use. These names are in the docstring located below the class definition so where I have findingCoordinates I should have Tool.
I hope this helps.
self refers to an instance of the class that you've defined, so to access those values, you need to create an instance of the class, call the method, and then access the values from the instance.
For example:
In [9]: %paste
class findingCoordinates(object):
"""Implementation for leetScripts_addin.tool (Tool)"""
def __init__(self):
self.enabled = True
self.shape = "NONE"
def onMouseDownMap(self, x, y, button, shift):
print "onMouseDowMap executing"
#this is where I declared the first two variables using self
self.x = x
self.y = y
print "Selected point is at %r, %r" % (self.x, self.y)
pass
## -- End pasted text --
In [10]: f = findingCoordinates()
In [11]: f.onMouseDownMap(x=1, y=2, button="button", shift="shift")
onMouseDowMap executing
Selected point is at 1, 2
In [12]: f.x
Out[12]: 1
In [13]: f.y
Out[13]: 2
EDIT: It seems like you've had some confusion about scoping/namespaces as well. There's no x or y defined globally; they just exist within the class instances. That will also allow you to have separate x and y values for different instances of the class.
In [14]: x
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-14-401b30e3b8b5> in <module>()
----> 1 x
NameError: name 'x' is not defined
In [15]: y
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-15-009520053b00> in <module>()
----> 1 y
NameError: name 'y' is not defined
In [16]: g = findingCoordinates()
In [17]: g.onMouseDownMap(100,200,0,0)
onMouseDowMap executing
Selected point is at 100, 200
In [18]: f.x, f.y
Out[18]: (1, 2)
In [19]: g.x, g.y
Out[19]: (100, 200)
Related
I have a code as follows:
class SifFile():
setting = {}
interesting_param = ['Temp', 'Pressure']
def __init__(self, get_param):
self.File_Type = "Andor Technology Multi-Channel File"
for k, v in get_param.items():
if SifFile.interesting_param in k:
SifFile.setting[k] = v
return SifFile.setting
get_parameter = {'Temp':75, 'Pressure':50, 'Helium':90, 'Exp':96}
sif = SifFile(get_parameter)
There is a big dict named get_parameter that has a few parameters and their values.
There is also a list named interesting_param that contains 2 elements.
What I want to do is to check which parameters from interesting_param list are present in the get_parameter dictionary and I want to save those parameters in an empty dict named setting
I tried running the above code, but it gives me the following error:
Traceback (most recent call last):
File "", line 16, in
sif = SifFile(get_parameter)
File "", line 8, in init
if SifFile.interesting_param in k:
TypeError: 'in ' requires string as left operand, not list
Expected output:
setting = {'Temp':75, 'Pressure':50}
Here is the code that will give you the expected answer:
class SifFile():
setting = {}
interesting_param = ['Temp', 'Pressure']
def __init__(self):
self.File_Type = "Andor Technology Multi-Channel File"
return
def func(self, get_param):
for k, v in get_param.items():
if k in SifFile.interesting_param:
SifFile.setting[k] = v
return SifFile.setting
get_parameter = {'Temp':75, 'Pressure':50, 'Helium':90, 'Exp':96}
sif = SifFile()
x=sif.func(get_parameter)
print(x)
I have created anothter funcion called "func" because "init()" cannot return a dictionary. It should only return "None".
Besides that, the condition statement within the for loop is changed.
The error is telling you what's wrong: you are trying to check if a key exists in a dict but the key that you're checking for isn't a string. Let's look at the line in question:
if SifFile.interesting_param in k:
The error thinks that SifFile.interesting_param is a list, so let's have a look at where you define that:
interesting_param = ['Temp', 'Pressure']
Oh yeah, that is a list. Since a list can't be a dict key it throws an error.
You need to loop through your items in interesting_param one by one to check whether they're in the dict. I've implemented that here, along with a range of other issues in your code, mainly surrounding how you'd implemented the class:
class SifFile():
"""
Class for holding and processing sif files.
"""
def __init__(self, params):
"""
Define the variables you want to use in your class
"""
self.file_type = "Andor Technology Multi-Channel File"
self.interesting_params = ['Temp', 'Pressure']
self.given_params = params
self.setting = {}
def get_settings(self):
"""
Return list of settings of interest
"""
# Look at every parameter of interest in turn
for param in self.interesting_params:
# Check to see if it is in the dict of given parameters
if param in self.given_params:
# If it is then add it to the setting dict
self.setting[param] = self.given_params[param]
# Return the setting dict once the loop is done
return self.setting
parameters = {'Temp':75, 'Pressure':50, 'Helium':90, 'Exp':96}
sif = SifFile(parameters)
print(sif.get_settings())
Note that your variables are now all instance variables rather than class variables (they start with self) because you're changing them, so they are unlikely to be the same for every class.
I'm developing an application that reads a message input from telegram with a set of variables, and then starts a game with the user. So I created a class that represents an instance of the game, making one game per chat possible:
class Battle:
def __init__(self, mainchat):
self.mainchat = mainchat
print('Instance of battle started on chat %s' % self.mainchat)
pcount = 0
team1 = []
team2 = []
p1 = ()
p2 = ()
p1score = 0
p2score = 0
battlechoicep1 = -1
battlechoicep2 = -1
so, as soon as I get a message, I start an instance of a battle based on user inputes, e.g.
battle = Battle(chat_id)
battle.p1 = 'Paul'
battle.battlechoicep1 = 4
...
this way has been working fine right now, but every time I want to reset the battle, I go through a function that does this:
battle.pcount = 0
battle.team1 = []
battle.team2 = []
battle.p1 = ()
battle.p2 = ()
battle.p1score = 0
battle.p2score = 0
battle.battlechoicep1 = -1
battle.battlechoicep2 = -1
save() # outside function that saves the scores into a pickle file
return
So, I would like to make it so this is a function inside my class, so everytime I call battle.reset it would call something like this
def reset():
battle.pcount = 0
battle.team1 = []
battle.team2 = []
battle.p1 = ()
battle.p2 = ()
battle.p1score = 0
battle.p2score = 0
battle.battlechoicep1 = -1
battle.battlechoicep2 = -1
save() # outside function that saves the scores into a pickle file
return
I don't know how is the right approach to this problem, I don't even know if what I've been doing up to now is 'correct' (it is working at least).
Creating the function inside the class (like def reset(self):) seems to have no effect.
You're on the right track with def reset(self). You just need to change the instances of battle to self in the method itself. NOTE: This needs to be a method of the Battle class.
def reset(self):
self.pcount = 0
... # etc
save() # outside function that saves the scores into a pickle file
When you pass in self as the first parameter of a class method, it allows the method to work on the instance of the class that you've called it on. If you just do def reset(self) without changing the battle to self, it will try to modify a variable in the current scope called battle, which in this case probably doesn't exist.
The other thing you could do if you just want reset to create a completely new object without preserving any of the attributes, you can just do:
def reset(self):
return Battle()
You're almost there!
class Battle:
def __init__(self, mainchat):
self.mainchat = mainchat
print('Instance of battle started on chat %s' % self.mainchat)
self.reset()
def reset(self):
self.team1, self.team2 = [], []
self.p1 = self.p2 = () #New tuples will be assigned and overwritten
self.pcount = self.p1score = self.p2score = 0
self.battlechoicep1 = self.battlechoicep2 = -1
save() # outside function that saves the scores into a pickle file
So when you need to reset, just call battle.reset()! Maybe the save function can also be a class method as well, just follow the same format.
I am writing a code for a project in particle physics (using pyroot).
In my first draft, I use the following line
for i in MyTree:
pion.SetXYZM(K_plus_PX, K_plus_PY, K_plus_PZ,K_plus_MM)
This basically assigns to the pion the values of variables in the parenthesis, ie momenta and inv. mass of the kaon.
Physics aside, I would like to write a function "of the form":
def myfunc(particle):
return %s_PX % particle
I know this is wrong. What I would like to achieve is to write a function that allows, for a given particle, to set particle_PX, particle_PY etc to be the arguments of SetXYZM.
Thank you for your help,
B
To access class attributes from string variables you can use python's getattr:
import ROOT
inputfile = ROOT.TFile.Open("somefile.root","read")
inputtree = inputfile.Get("NameOfTTree")
inputtree.Print()
# observe that there are branches
# K_plus_PX
# K_plus_PY
# K_plus_PZ
# K_plus_MM
# K_minus_PX
# K_minus_PY
# K_minus_PZ
# K_minus_MM
# pi_minus_PX
# pi_minus_PY
# pi_minus_PZ
# pi_minus_MM
def getx(ttree,particlename):
return getattr(ttree,particlename+"_PX")
def gety(ttree,particlename):
return getattr(ttree,particlename+"_PY")
def getz(ttree,particlename):
return getattr(ttree,particlename+"_PZ")
def getm(ttree,particlename):
return getattr(ttree,particlename+"_MM")
def getallfour(ttree,particlename):
x = getattr(ttree,particlename+"_PX")
y = getattr(ttree,particlename+"_PY")
z = getattr(ttree,particlename+"_PZ")
m = getattr(ttree,particlename+"_MM")
return x,y,z,m
for entry in xrange(inputtree.GetEntries()):
inputtree.GetEntry(entry)
pion1 = ROOT.TLorentzVector()
x = getx(inputtree,"K_plus")
y = gety(inputtree,"K_plus")
z = getz(inputtree,"K_plus")
m = getm(inputtree,"K_plus")
pion2.SetXYZM(x,y,z,m)
x,y,z,m = getallfour(inputtree,"pi_minus")
pion2 = ROOT.TLorentzVector()
pion2.SetXYZM(x,y,z,m)
As linked by Josh Caswell, you can similarly access variable names:
def getx(particlename):
x = globals()[partilcename+"_PX"]
though that might get nasty quickly as of whether your variables are global or local and for local, in which context.
I am trying to go through a list of class objects in my program, and access functions belonging to the objects.
I am using this method :
# - - - Grid Updating
def update_grid(self):
for i in range(len(self.populationList)):
self.populationList[i].operate
To access this object type :
class Dotian():
goal = '#'
log = []
position = (0,0)
def __init__(self):
self.name = ops.randomLine('data/names')
def operate(self):
print 'here'
The list is populated like so :
# - - - Spawning Dotian
def spawn_dotian(self):
coord = ops.randomCoordinates(0, self.width-1)
if self.grid[coord[0]][coord[1]] == 0 :
spawnDot = Dotian
spawnDot.position = coord
self.populationList.append(spawnDot)
self.grid[coord[0]][coord[1]] = 1
else :
self.spawn_dotian()
The program should print here but it doesn't print anything.
Using python 2.7.3
I'm trying to make a robotics kit. Its designed to be simple so I'm using properties so when the users change a parameter the property method sends the serial command which controls motors/ servos/whatever.
This is the code at the moment, directly from a previous question I asked on here.
class Servo(object):
def __init__(self, which_servo, angle = 0):
self._angle = angle;
self._servo_no = which_servo
def get_angle(self):
return self._angle
def set_angle(self, value):
self._angle = value
print "replace this print statement with the code to set servo, notice that this method knows the servo number AND the desired value"
def del_angle(self):
del self._angle
angle = property(get_angle, set_angle, del_angle, "I'm the 'angle' property.
this is then initialized as such:
class robot(object):
def __init___(self):
self.servos = [Servo(0), Servo(1), Servo(2), Servo(3)]
Now, this works in the respect that it does change the variable through the getter and setter functions, however the prints in the getter and setter never is printed, thus if I replace it with a serial command I assume it won't do anything either, can anyone shed any light on this?
Thanks
Update: Thanks for the help using the servo file this is whats happened, there are three scenarios the first works and by extension I would have assumed the next two preferable scenarios would work but they don't any ideas?
This works
import servo
class Robot(object):
def __init__(self):
self.servos = [servo.Servo(0, 0), servo.Servo(1,0), servo.Servo(2,0)]
R = Robot()
R.servos[1].angle = 25
This does not:
import servo
class Robot(object):
def __init__(self):
self.servos = [servo.Servo(0, 0), servo.Servo(1,0), servo.Servo(2,0)]
R = Robot()
left_servo = R.servos[1].angle
left_servo = 25
Neither does this
import servo
class Robot(object):
def __init__(self):
self.servos = [servo.Servo(0, 0).angle, servo.Servo(1,0).angle, servo.Servo(2,0).angle]
R = Robot()
R.servo[1] = 25
Using the preferred decorator syntax for properties, this works fine. It'll also help you avoid issues like this in the future
class Servo(object):
def __init__(self, which_servo, angle = 0):
self._angle = angle;
self._servo_no = which_servo
#property
def angle(self):
return self._angle
#angle.setter
def angle(self, value):
self._angle = value
print "replace this print statement with the code to set servo"
#angle.deleter
def angle(self):
del self._angle
Seeing as your indentation is off here, I believe this is likely an issue of indentation in your source. This should work as well if you really want to use the old property function:
class Servo(object):
def __init__(self, which_servo, angle = 0):
self._angle = angle;
self._servo_no = which_servo
def get_angle(self):
return self._angle
def set_angle(self, value):
self._angle = value
print "replace this print statement with the code to set servo"
def del_angle(self):
del self._angle
angle = property(get_angle, set_angle, del_angle,"I'm the 'angle' property.")
Both of these work successfully for me (inside a file called servo.py)
>>> import servo
>>> s = servo.Servo(1, 2)
>>> s.angle
2
>>> s.angle = 3
replace this print statement with the code to set servo
EDIT
To address your new issues. When you assign R.servos[1].angle to left_servo, its not creating a reference to the servos angle, it's just setting left_servo to whatever the angle is. When you reassign 25 to it, you're not assigning to the angle you're assigning to the left_servo.
On the second one, I'm assuming you meant R.servos and not R.servo which should be raising an AttributeError. But the real problem as I see it, is you should be saying R.servos[1].angle = 25 and you're omitting the .angle.
To (attempt to) put it simply: When you use the = operator, you are changing where a name refers to, not what it refers to.
>>> x = 1
>>> x = 2
the second assignment does not overwrite the 1 in memory with a 2, it just changes where x refers to. So if I did something like
>>> x = 1
>>> y = x
>>> y = 2
>>> print x
1
the output is 1 because your are telling y to refer to the same place that x refers. Changing y to 2 changes where y refers to, it does not change the 1 already in memory.