I am trying to call a function from within a function, and the former calls more functions etc.
import ROOT as root
import sys, math
class SFs():
def __init__(self):
self.get_EfficiencyData = None
self.get_EfficiencyMC = None
self.get_ScaleFactor = None
self.eff_dataH = None
self.eff_mcH = None
self.get_ScaleFactor = None
self.get_EfficiencyMC = None
def ScaleFactor(self,inputRootFile):
self.eff_dataH = root.std.map("string", root.TGraphAsymmErrors)()
self.eff_mcH = root.std.map("string", root.TGraphAsymmErrors)()
EtaBins=["Lt0p9", "0p9to1p2","1p2to2p1","Gt2p1"]
fileIn = root.TFile(inputRootFile,"read")
HistoBaseName = "Label"
etaBinsH = fileIn.Get("Bins")
# etaLabel, GraphName
nEtaBins = int(etaBinsH.GetNbinsX())
for iBin in range (0, nEtaBins):
etaLabel = EtaBins[iBin]
GraphName = HistoBaseName+etaLabel+"_Data"
print GraphName,etaLabel
self.eff_dataH[etaLabel]=fileIn.Get(str(GraphName))
self.eff_mcH[etaLabel]=fileIn.Get("histo")
print self.eff_mcH[etaLabel].GetXaxis().GetNbins()
print self.eff_mcH[etaLabel].GetX()[5]
self.get_ScaleFactor(46.8,2.0)
def get_ScaleFactor(self,pt, eta):
efficiency_mc = get_EfficiencyMC(pt, eta)
if efficiency_mc != 0.:
SF = 1/float(efficiency_mc)
else:
SF=1.
return SF
def get_EfficiencyMC(self,pt, eta):
label = FindEtaLabel(eta,"mc")
# label= "Lt0p9"
binNumber = etaBinsH.GetXaxis().FindFixBin(eta)
label = etaBinsH.GetXaxis().GetBinLabel(binNumber)
ptbin = FindPtBin(eff_mcH, label, pt)
Eta = math.fabs(eta)
print "eff_mcH ==================",eff_mcH,binNumber,label,ptbin
# ptbin=10
if ptbin == -99: eff =1
else: eff= eff_mcH[label].GetY()[ptbin-1]
if eff > 1.: eff = -1
if eff < 0: eff = 0.
print "inside eff_mc",eff
return eff
sf = SFs()
sf.ScaleFactor("Muon_IsoMu27.root")
I want to call the get_ScaleFactor() which in turn calls the get_EfficiencyMC() etc, but I once trying calling the former, I get TypeError: 'NoneType' object is not callable
in your class init you define:
self.get_EfficiencyMC = None
and later define a function (i.e. class method)
def get_EfficiencyMC(self,pt, eta):
when you create an instance of the class, the init part is executed shadowing the class method. Just either remove it from the init, or change the method name.
Related
How can I get the value of an intSliderGrp defined inside a class and use it on a function outside said class?
I'm trying to get my main UI all inside a class so I can just call it inside maya, but I need the value set on a slider to modify a function outside the classUI:
import maya.cmds as cmds
def setSubdivision(*args):
obj = cmds.ls(sl = True)
asubd = cmds.intSliderGrp(sliderSet, query = True , value = True)
for i in obj:
cmds.setAttr('%s.aiSubdivIterations' %i, int(asubd))
class subdivisionUI():
windowName = "ArnoldSubdivisionWindow"
def show(self):
if cmds.window(self.windowName, query = True, exists = True, width = 150):
cmds.deleteUI(self.windowName)
cmds.window(self.windowName)
mainColumn = cmds.columnLayout(adjustableColumn = True)
cmds.text(l='Set subdivisions to selected objects', al = 'center')
column2 = cmds.rowLayout(numberOfColumns = 2, adjustableColumn=2, columnAlign=(1, 'right'))
sliderSet = cmds.intSliderGrp(l = "Subdivisions", s =1, min = 0, max = 20, field = True)
b = cmds.button(l = 'Set')
cmds.button(b, e = True , command = setSubdivision, width = 50 )
cmds.showWindow()
subdivisionUI().show()
It's my first time using classes so I'm still trying to understand how they work and the proper use.
At the moment you do not use the advantage of classes for UI creation in Maya. The big advantage is that you can keep everything encapsulated in this class without the need of any external functions or global variables. If you try this approach your problem disappears:
import maya.cmds as cmds
class subdivisionUI():
windowName = "ArnoldSubdivisionWindow"
def __init__(self):
if cmds.window(self.windowName, query = True, exists = True, width = 150):
cmds.deleteUI(self.windowName)
self.window = cmds.window(self.windowName)
mainColumn = cmds.columnLayout(adjustableColumn = True)
cmds.text(l='Set subdivisions to selected objects', al = 'center')
column2 = cmds.rowLayout(numberOfColumns = 2, adjustableColumn=2, columnAlign=(1, 'right'))
self.sliderSet = cmds.intSliderGrp(l = "Subdivisions", s =1, min = 0, max = 20, field = True)
b = cmds.button(l = 'Set')
cmds.button(b, e = True , command = self.setSubdivision, width = 50 )
def setSubdivision(self, *args):
obj = cmds.ls(sl = True)
asubd = cmds.intSliderGrp(self.sliderSet, query = True , value = True)
for i in obj:
cmds.setAttr('%s.aiSubdivIterations' %i, int(asubd))
def show(self):
cmds.showWindow(self.window)
subdivisionUI().show()
I have the following code in main.py:
import json
from data import message # data.py
from definitions import * # definitions.py
waypoints=[]
stations=[]
genes = []
jsonObj = json.loads(message) # from data.py
for item in jsonObj:
location = Location(id=item["id"], name=item["name"], lat=item["lat"], lon=item["lon"])
if ("is-start" in item) or ("is-end" in item):
location.isWaypoint = True
if "is-start" in item:
start = location
else:
end = location
else:
genes.append(location)
if "is-waypoint" in item:
location.isWaypoint = True
waypoints.append(location)
else:
stations.append(location)
Then, I have the following code in definitions.py:
from haversine import haversine
start = None
end = None
distMatrix = {}
def distBtwn(loc1, loc2):
dist = 0
pair = frozenset((loc1.id, loc2.id))
if pair in distMatrix:
dist = distMatrix[pair]
else:
coords1 = (loc1.lat, loc2.lon)
coords2 = (loc2.lat, loc2.lon)
dist = haversine(coords1, coords2)
distMatrix[pair] = dist
return dist
class Location:
def __init__(self, id, name, lat, lon):
self.id = id
self.name = name
self.lat = lat
self.lon = lon
self.isWaypoint = False
def __repr__(self):
rep = ""
if self.isWaypoint:
rep += "Waypoint "
else:
rep += "Station "
rep += "%d: %s (%f, %f)" % (self.id, self.name, self.lat, self.lon)
return rep
class Fitness:
def __init__(self, route):
self.route = route
self.distance = 0.0
self.fitness = 0.0
def routeDistance(self):
if self.distance = 0.0:
global start
global end
print(start)
print(self.route[0])
print(self.route[-1])
print(end)
pathDistance = distBtwn(start, self.route[0]) + distBtwn(self.route[-1], end)
for i in range(len(self.route) - 1):
pathDistance += distBtwn(self.route[i], self.route[i + 1])
self.distance = pathDistance
return self.distance
I run main.py, then entered the following in the shell, which throws an error:
>>> start
Waypoint 0: startPoint (3.333333, 3.333333)
>>> end
Waypoint 2: endPoint (4.444444, 4.444444)
>>> route = [waypoints[0], stations[15], waypoints[1]]
>>> fitA = Fitness(route)
>>> fitA.routeDistance()
None
Waypoint 1: waypointA (1.111111, 1.111111)
Waypoint 3: waypointC (2.222222, 2.222222)
None
Traceback (most recent call last):
File "<pyshell#78>", line 1, in <module>
fitA.routeDistance()
File "definitions.py", line 54, in routeDistance
pathDistance = distBtwn(start, self.route[0]) + distBtwn(self.route[-1], end)
File "definitions.py", line 10, in distBtwn
pair = frozenset((loc1.id, loc2.id))
AttributeError: 'NoneType' object has no attribute 'id'
>>> start
Waypoint 0: startPoint (3.333333, 3.333333)
>>> end
Waypoint 2: endPoint (4.444444, 4.444444)
Based on the above, routeDistance() is using the original None values of start and end from initialisation, even though they've been declared as global variables. Yet when called from the shell, those two variables have already been updated correctly with Location objects assigned. What is going wrong here?
Global variables are scoped to a module.
For example, in foo.py:
def set_variable(to):
global variable
variable = to
variable = None
And bar.py:
import foo
def get_variable():
global variable # Unnecessary, but to avoid confusion
return variable
variable = 1
print(foo.variable) # None
foo.set_variable(2) # Sets `foo`'s global variable to `2`
print(get_variable()) # 1; `bar`'s global variable is still 1
print(foo.variable) # 2; `foo`'s global variable is now `2`
You need to set definitions.start and definitions.stop.
I read several post about the nested class, but this mechanism is still not clear for me.
Basically what I want to do is define a class (to solve ordinary differential equation in which I define one class for each order of accuracy )
Here's the class :
class AdamsBashforth(AdamsMethods):
class _2nd(AdamsMethods):
startup = False
def __init__(self, dydt : Rhs, filename :str = None , salve : bool = True ):
self.file = filename
self.save = save
super().__init__(dydt)
def solve(self):
self.time , self.u = self.dydt.createArray()
u[1] = rungekutta.RK2.step(self.dydt.f, time[0], u[0], self.dt)
for i in range(1,len(self.time)-1):
self.u[i+1] = u[i] + self.dt/2*(3*self.dydt.f(self.time[i],self.u[i])-self.dydt.f(self.time[i-1],self.u[i-1]))
AdamsBashforth._2nd.solved = True
if self.file != None:
super().write2file()
if self.save:
return self.time,self.u
def plot(self):
if AdamsBashforth._2nd.solved:
super().plot('Sys ODE solution using Adams-Bashforth 2nd order','time [s]','y(t)')
else:
print("Unsolved problem, call `solve` method before")
#classmethod
def step(cls, func , t : np.float , u : np.float, dt ):
def f(ti,ui):
return np.array([function(ti,ui) for function in func])
if AdamsBashforth._2nd.startup == False:
#print ("AB start-up")
AdamsBashforth.u1 = rungekutta.RK2.step(func,t,u,dt)
AdamsBashforth.startup = True
unext = AdamsBashforth.u1 + dt/2.*(3.*f(t+dt,AdamsBashforth.u1) - f(t,u))
AdamsBashforth.u1 = u
return unext
Here's the way that I would really like to do is to call:
problem = AdamsBashforth._2nd(dydt)
but i receive an error that says that adamsbashforth has no member _2nd
so I've try to doing so .. but still the same message :
class AdamsBashforth(AdamsMethods):
def __init__(self, dydt, filename :str = None , salve : bool = True):
self._2nd = self._2nd(dydt,filename,salve)
def solve(self):
pass
class _2nd(AdamsMethods):
What is the right way in order to obtain a call like the first (problem = AdamsBashforth._2nd(dydt))
and using the class _2nd
EDIT
class AdamsBashforth(AdamsMethods):
def __init__(self, dydt, filename :str = None , save : bool = True):
self._2nd = AdamsBashforth._2nd(dydt,filename,save)
def solve(self):
pass
class _2nd(AdamsMethods):
startup = False
solved = False
def __init__(self, dydt : Rhs, filename :str = None , save : bool = True ):
self.file = filename
self.save = save
super().__init__(dydt)
def solve(self):
self.time , self.u = self.dydt.createArray()
self.u[1] = rungekutta.RK2.step(self.dydt.f, self.time[0], self.u[0], self.dt)
for i in range(1,len(self.time)-1):
self.u[i+1] = u[i] + self.dt/2*(3*self.dydt.f(self.time[i],self.u[i])-self.dydt.f(self.time[i-1],self.u[i-1]))
_2nd.solved = True
if self.file != None:
super().write2file()
if self.save:
return self.time,self.u
def plot(self):
if AdamsBashforth._2nd.solved:
super().plot('Sys ODE solution using Adams-Bashforth 2nd order','time [s]','y(t)')
else:
print("Unsolved problem, call `solve` method before")
#classmethod
def step(cls, func , t : np.float , u : np.float, dt ):
def f(ti,ui):
return np.array([function(ti,ui) for function in func])
if AdamsBashforth._2nd.startup == False:
#print ("AB start-up")
AdamsBashforth.u1 = rungekutta.RK2.step(func,t,u,dt)
AdamsBashforth.startup = True
unext = AdamsBashforth.u1 + dt/2.*(3.*f(t+dt,AdamsBashforth.u1) - f(t,u))
AdamsBashforth.u1 = u
return unext
calling in this way :
ab2_p1 = adamsmethods.AdamsBashforth(problem1, 'ab2_1.dat')
ab2t,ab2u = ab2_p1._2nd.solve()
ab2_p1.plot()
looks that work .. but I don't know why ... and I don't know if is it the correct way !!
but I have still problem in order to call the classmethod for example :
u = adamsmethods.AdamsBashforth._2nd.step(func0,t,u,dt)
doesn't work :
Traceback (most recent call last):
File "drive.py", line 287, in <module>
main()
File "drive.py", line 149, in main
u = adamsmethods.AdamsBashforth._2nd.step(func0,t,u,dt)
AttributeError: type object '_2nd' has no attribute 'step'
------------------------------------------------------------
I'm writing a class for a simple game of 4 in a row, but I'm running into a problem calling a method in the same class. Here's the whole class for the sake of completeness:
class Grid:
grid = None
# creates a new empty 10 x 10 grid
def reset():
Grid.grid = [[0] * 10 for i in range(10)]
# places an X or O
def place(player,x,y):
Grid.grid[x][y] = player
# returns the element in the grid
def getAt(x,y):
return Grid.grid[x][y]
# checks for wins in a certain direction
def checkLine(player,v,count,x,y):
x = x+v[0]
y = y+v[1]
if x < 0 or x > 9:
return
if y < 0 or y > 9:
return
if Grid.grid[x][y] == p:
count = count+1
if count == 4:
return True
checkLine(player,v,count,x,y)
return False
# returns the number of the player that won
def check():
i = 'i'
for x in range(0,10):
for y in range(0,10):
if Grid.grid[x][y] > 0:
p = Grid.grid[x][y]
f = checkLine(p,0,array(i,[1,0]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[0,1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[1,1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[-1,0]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[0,-1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[-1,-1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[1,-1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[-1,1]),x,y)
if f:
return p
return 0
reset = staticmethod(reset)
place = staticmethod(place)
getAt = staticmethod(getAt)
check = staticmethod(check)
checkLine = staticmethod(checkLine)
I'm trying to call checkLine() from check(), but I get the error "NameError: global name 'checkLine' is not defined". When I call Grid.checkLine() instead, I get "TypeError: 'module' object is not callable"
How do I call checkLine()?
EDIT:
#beer_monk
class Grid(object):
grid = None
# creates a new empty 10 x 10 grid
def reset(self):
Grid.grid = [[0] * 10 for i in range(10)]
# places an X or O
def place(self,player,x,y):
Grid.grid[x][y] = player
# returns the element in the grid
def getAt(self,x,y):
return Grid.grid[x][y]
# checks for wins in a certain direction
def checkLine(self,player,v,count,x,y):
x = x+v[0]
y = y+v[1]
if x < 0 or x > 9:
return
if y < 0 or y > 9:
return
if Grid.grid[x][y] == p:
count = count+1
if count == 4:
return True
checkLine(self,player,v,count,x,y)
return False
# returns the number of the player that won
def check(self):
i = 'i'
for x in range(0,10):
for y in range(0,10):
if Grid.grid[x][y] > 0:
p = Grid.grid[x][y]
for vx in range(-1,2):
for vy in range(-1,2):
f = self.checkLine(p,0,array(i,[vx,vy]),x,y)
if f:
return p
return 0
reset = staticmethod(reset)
place = staticmethod(place)
getAt = staticmethod(getAt)
check = staticmethod(check)
checkLine = staticmethod(checkLine)
Get rid of the class. Use plain functions and module level variable for grid.
The class is not helping you in any way.
PS. If you really want to call checkline from within the class, you'd call Grid.checkline. For example:
class Foo:
#staticmethod
def test():
print('Hi')
#staticmethod
def test2():
Foo.test()
Foo.test2()
prints
Hi
Syntax:
class_Name.function_Name(self)
Example:
Turn.checkHoriz(self)
A reworked example (hopefully showing a better use of classes!)
import itertools
try:
rng = xrange # Python 2.x
except NameError:
rng = range # Python 3.x
class Turn(object):
def __init__(self, players):
self.players = itertools.cycle(players)
self.next()
def __call__(self):
return self.now
def next(self):
self.now = self.players.next()
class Grid(object):
EMPTY = ' '
WIDTH = 10
HEIGHT = 10
WINLENGTH = 4
def __init__(self, debug=False):
self.debug = debug
self.grid = [Grid.EMPTY*Grid.WIDTH for i in rng(Grid.HEIGHT)]
self.player = Turn(['X','O'])
def set(self, x, y):
if self.grid[y][x]==Grid.EMPTY:
t = self.grid[y]
self.grid[y] = t[:x] + self.player() + t[x+1:]
self.player.next()
else:
raise ValueError('({0},{1}) is already taken'.format(x,y))
def get(self, x, y):
return self.grid[y][x]
def __str__(self):
corner = '+'
hor = '='
ver = '|'
res = [corner + hor*Grid.WIDTH + corner]
for row in self.grid[::-1]:
res.append(ver + row + ver)
res.append(corner + hor*Grid.WIDTH + corner)
return '\n'.join(res)
def _check(self, s):
if self.debug: print("Check '{0}'".format(s))
# Exercise left to you!
# See if a winning string exists in s
# If so, return winning player char; else False
return False
def _checkVert(self):
if self.debug: print("Check verticals")
for x in rng(Grid.WIDTH):
winner = self._check([self.get(x,y) for y in rng(Grid.HEIGHT)])
if winner:
return winner
return False
def _checkHoriz(self):
if self.debug: print("Check horizontals")
for y in rng(Grid.HEIGHT):
winner = self._check([self.get(x,y) for x in rng(Grid.WIDTH)])
if winner:
return winner
return False
def _checkUpdiag(self):
if self.debug: print("Check up-diagonals")
for y in rng(Grid.HEIGHT-Grid.WINLENGTH+1):
winner = self._check([self.get(d,y+d) for d in rng(min(Grid.HEIGHT-y, Grid.WIDTH))])
if winner:
return winner
for x in rng(1, Grid.WIDTH-Grid.WINLENGTH+1):
winner = self._check([self.get(x+d,d) for d in rng(min(Grid.WIDTH-x, Grid.HEIGHT))])
if winner:
return winner
return False
def _checkDowndiag(self):
if self.debug: print("Check down-diagonals")
for y in rng(Grid.WINLENGTH-1, Grid.HEIGHT):
winner = self._check([self.get(d,y-d) for d in rng(min(y+1, Grid.WIDTH))])
if winner:
return winner
for x in rng(1, Grid.WIDTH-Grid.WINLENGTH+1):
winner = self._check([self.get(x+d,d) for d in rng(min(Grid.WIDTH-x, Grid.HEIGHT))])
if winner:
return winner
return False
def isWin(self):
"Return winning player or False"
return self._checkVert() or self._checkHoriz() or self._checkUpdiag() or self._checkDowndiag()
def test():
g = Grid()
for o in rng(Grid.WIDTH-1):
g.set(0,o)
g.set(Grid.WIDTH-1-o,0)
g.set(Grid.WIDTH-1,Grid.HEIGHT-1-o)
g.set(o,Grid.HEIGHT-1)
print(g)
return g
g = test()
print g.isWin()
Unlike java or c++, in python all class methods must accept the class instance as the first variable. In pretty much every single python code ive seen, the object is referred to as self. For example:
def reset(self):
self.grid = [[0] * 10 for i in range(10)]
See http://docs.python.org/tutorial/classes.html
Note that in other languages, the translation is made automatically
There are multiple problems in your class definition. You have not defined array which you are using in your code. Also in the checkLine call you are sending a int, and in its definition you are trying to subscript it. Leaving those aside, I hope you realize that you are using staticmethods for all your class methods here. In that case, whenever you are caling your methods within your class, you still need to call them via your class's class object. So, within your class, when you are calling checkLine, call it is as Grid.checkLine That should resolve your NameError problem.
Also, it looks like there is some problem with your module imports. You might have imported a Module by name Grid and you have having a class called Grid here too. That Python is thinking that you are calling your imported modules Grid method,which is not callable. (I think,there is not a full-picture available here to see why the TypeError is resulting)
The best way to resolve the problem, use Classes as they are best used, namely create objects and call methods on those objects. Also use proper namespaces. And for all these you may start with some good introductory material, like Python tutorial.
Instead of operating on an object, you are actually modifying the class itself. Python lets you do that, but it's not really what classes are for. So you run into a couple problems
-You will never be able to make multiple Grids this way
the Grid can't refer back to itself and e.g. call checkLine
After your grid definition, try instantiating your grid and calling methods on it like this
aGrid = Grid()
...
aGrid.checkLine()
To do that you, you first need to modify all of the method definitions to take "self" as your first variable and in check, call self.checkLine()
def check(self):
...
self.checkLine()
...
Also, your repeated checking cries out for a FOR loop. You don't need to write out the cases.
Java programmer as well here, here is how I got it to call an internal method:
class Foo:
variable = 0
def test(self):
self.variable = 'Hi'
print(self.variable)
def test2(self):
Foo.test(self)
tmp = Foo()
tmp.test2()
class Teller(object):
def __init__(self):
self.occupied = False
self.timeLeft = 0
self.totTime
def occupy(self, timeOcc):
self.occupied = True
self.timeLeft = timeOcc
def nextMin(self):
self.timeLeft -= 1
self.totTime += 1
if self.timeLeft == 0:
self.occupied = False
class Bank(object):
def __init__(numTellers, hoursOpen):
self.tellers = []
self.timeWaited = 0
self.clientsWaiting = []
for x in xrange(numTellers):
tempTeller = Teller.__init__()
self.tellers.append(tempTeller)
self.minutesOpen = hoursOpen * 60
def tellerOpen(self):
for x in xrange(len(self.tellers)):
if not self.tellers[x].occupied:
return x+1
return 0
def runSim(self, queueInput): #queueInput is a list of tuples (time, timeAtTeller)
simTime = self.minutesOpen
totCli = 0
timeToNext = queueInput[0][0]
timeAtNext = queueInput[0][1]
queueInput.pop(0)
self.clientsWaiting.append([timeToNext, timeAtNext])
while simTime > 0:
for person in self.clientsWaiting:
if person[0]:
person -= 1
if not self.clientsWaiting[len(self.clientsWaiting)-1][0]:
timeToNext = queueInput[0][0]
timeAtNext = queueInput[0][1]
queueInput.pop(0)
self.clientsWaiting.append([timeToNext, timeAtNext])
remove = 0
for x in xrange (len(self.clientsWaiting)-1):
if tellerOpen() and not self.clientsWaiting[x][0]:
self.tellers[tellerOpen()].occupy(self.clientsWaiting[x][0])
totCli += 1
remove += 1
elif not tellerOpen() and not self.clientsWaiting[x][0]:
self.timeWaited += 1
for x in xrange(remove):
self.clientsWaiting.pop(x)
print """The total time spent in the queue by all clients was %d minutes. The total number of clients today was %d. The average waiting time was %d mins""" % (self.timeWaited, totCli, self.timeWaited / totCli)\
if __name__ == '__main__':
inp = raw_input()
tList = inp.split('\n')
qList = []
for item in tList:
tList = item.split(' ')
qList.append((tList[0], tList[1]))
virtBank = Bank.__init__(3, 7)
bank.runSim(qList)
This results in this error:
> TypeError: unbound method __init__() must be called with Bank instance as first argument (got int instance instead)
I don't see what I've dont wrong. Any advice would be appreciated.
The only important parts, I think, are the Bank class __init__ and the call virtBank = Bank.__init__(3, 7)
2 points to make here:
You shouldn't be calling __init__ directly, it's a magic method which is invoked when you construct an object like this:
virtBank = Bank(3, 7)
The instance is implicitly passed to the constructor, but it must be explicitly received, like this:
def __init__(self, numTellers, hoursOpen):
# ...