I am getting an error about TypeError: 'staticmethod' object is not callable. Basically, you the input is a map of and given that you provide a pair of floats (pt,eta), the code should return the Y value of the bin that the particular values fall in.
I ve tried related thread (as possible duplicates) but does not seem to be getting the answer I am looking for.
Of course, if one has any recommendations how to even improve the code, that would be welcomed of course.
import ROOT as root
import sys,math
class SFs():
global etaBinsH
global get_EfficiencyData
global get_EfficiencyMC
global eff_dataH
global eff_mcH
global get_ScaleFactor
@staticmethod
def ScaleFactor(inputRootFile) :
#inputRootFile="Muon_IsoMu27.root"
eff_dataH = root.std.map("string", root.TGraphAsymmErrors)()
eff_mcH = root.std.map("string", root.TGraphAsymmErrors)()
#std::map<std::string, root.TGraphAsymmErrors *> eff_data
#std::map<std::string, root.TGraphAsymmErrors *> eff_mc
EtaBins=["Lt0p9", "0p9to1p2","1p2to2p1","Gt2p1"]
print inputRootFile
fileIn = root.TFile(inputRootFile,"read")
fileIn.ls()
HistoBaseName = "ZMassEta"
etaBinsH = fileIn.Get("etaBinsH")
#etaLabel, GraphName
nEtaBins = int(etaBinsH.GetNbinsX())
eff_data= []
eff_mc= []
#eff_mcH =root.TGraphAsymmErrors()
print "EtaBins...........",nEtaBins, len(EtaBins)
for iBin in range (0, nEtaBins) :
etaLabel = EtaBins[iBin]
GraphName = HistoBaseName+etaLabel+"_Data"
print GraphName,etaLabel
eff_data.append(fileIn.Get(str(GraphName)))
eff_dataH[etaLabel]=fileIn.Get(str(GraphName))
GraphName = HistoBaseName+etaLabel+"_MC"
eff_mc.append(fileIn.Get(str(GraphName)))
eff_mcH[etaLabel]=fileIn.Get(str(GraphName))
print eff_mcH[etaLabel].GetXaxis().GetNbins()
print eff_mcH[etaLabel].GetX()[5]
sff = get_ScaleFactor(46.8,2.0)
print "SFFFFFFFFFFFFFf",sff
@staticmethod
def get_ScaleFactor(pt, eta) :
efficiency_data = get_EfficiencyData(pt, eta)
efficiency_mc = get_EfficiencyMC(pt, eta)
if efficiency_mc != 0. :
SF = float(efficiency_data)/float(efficiency_mc)
else :
SF=1.
print "ScaleFactor::get_ScaleFactor(double pt, double eta) Scale Factor set to",SF,efficiency_data,efficiency_mc
return SF
@staticmethod
def get_EfficiencyMC(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
@staticmethod
def get_EfficiencyData(pt, eta) :
label = FindEtaLabel(eta,"data")
#label= "Lt0p9"
binNumber = etaBinsH.GetXaxis().FindFixBin(eta)
label = etaBinsH.GetXaxis().GetBinLabel(binNumber)
print eff_dataH
ptbin = FindPtBin(eff_dataH, label, pt)
Eta = math.fabs(eta)
fileOut=root.TFile("out.root","recreate")
fileOut.cd()
eff_dataH[label].Write(label)
#ptbin=10
if ptbin == -99 : eff =1
else : eff= eff_dataH[label].GetY()[ptbin-1]
print "inside eff_data",eff
if eff > 1. : eff = -1
if eff < 0 : eff = 0.
print "inside eff_data",eff,pt,eta,label
return eff
@staticmethod
def FindPtBin( eff_map, EtaLabel, Pt) :
Npoints = eff_map[EtaLabel].GetN()
print Npoints, "for ===============>",eff_map[EtaLabel],eff_map[EtaLabel].GetN(),EtaLabel
#ptMAX=100
#ptMIN=90
ptMAX = (eff_map[EtaLabel].GetX()[Npoints-1])+(eff_map[EtaLabel].GetErrorXhigh(Npoints-1))
ptMIN = (eff_map[EtaLabel].GetX()[0])-(eff_map[EtaLabel].GetErrorXlow(0))
if Pt >= ptMAX : return Npoints
elif Pt < ptMIN :
return -99
else : return eff_map[EtaLabel].GetXaxis().FindFixBin(Pt)
@staticmethod
def FindEtaLabel(Eta, Which) :
Eta = math.fabs(Eta)
binNumber = etaBinsH.GetXaxis().FindFixBin(Eta)
EtaLabel = etaBinsH.GetXaxis().GetBinLabel(binNumber)
it=-1
if str(Which) == "data" :
it = eff_dataH.find(EtaLabel)
if str(Which) == "mc" :
it = eff_mcH.find(EtaLabel)
return EtaLabel
sf = SFs()
sff = sf.ScaleFactor("Muon_IsoMu27.root")
Some examples that might be helpful to see what is going on.
class RandomClass():
global global_function
@staticmethod
def random_function(input):
print(global_function("test"))
return "random_function({})".format(input)
@staticmethod
def global_function(input):
return "global_function({})".format(input)
rc = RandomClass()
print(rc.random_function("Input!"))
Outputs
Traceback (most recent call last):
File "test.py", line 14, in <module>
print(rc.random_function("Input!"))
File "test.py", line 6, in random_function
print(global_function("test"))
TypeError: 'staticmethod' object is not callable
class RandomClass():
@staticmethod
def random_function(input):
print(global_function("test"))
return "random_function({})".format(input)
@staticmethod
def global_function(input):
return "global_function({})".format(input)
rc = RandomClass()
print(rc.random_function("Input!"))
Output
Traceback (most recent call last):
File "test.py", line 12, in <module>
print(rc.random_function("Input!"))
File "test.py", line 4, in random_function
print(global_function("test"))
NameError: global name 'global_function' is not defined
class RandomClass():
@staticmethod
def random_function(input):
print(RandomClass.global_function("test")) # Notice change here.
return "random_function({})".format(input)
@staticmethod
def global_function(input):
return "global_function({})".format(input)
rc = RandomClass()
print(rc.random_function("Input!"))
Output
global_function(test)
random_function(Input!)
In short, a @staticmethod
cannot access functions within its this
class (whether defined with this
or global
), and instead must initialize a new and independent class to call a function within the class it resides in (example 3). As @C.Nivs mentioned, you should perhaps look into simply not using a class.
To piggyback a bit on @Felipe's answer, by not making all of your methods static
, you can eliminate the need for the global
declarations to share variables around, since that's what you are doing anyways:
class SFs():
def __init__(self):
# initialize your global vars instead as
# instance variables
self.etaBinsH = None
self.get_EfficiencyData = None
self.get_EfficiencyMC = None
self.eff_dataH = None
self.get_ScaleFactor = None
# don't make this static, then you have access to the self attributes and it makes
# your code a bit more explicit
def scale_factor(self, input_file):
self.eff_dataH = root.std.map("string", root.TGraphAsymmErrors)()
self.eff_mcH = root.std.map("string", root.TGraphAsymmErrors)()
EtaBins = ["Lt0p9", "0p9to1p2","1p2to2p1","Gt2p1"]
print(input_file) # print with parentheses makes this more portable between versions
fileIn = root.TFile(input_file, "read")
# Now you can use this through self, which is more pythonic
self.etaBinsH = fileIn.Get("etaBinsH")
nEtaBins = int(self.etaBinsH.GetNbinsX())
eff_data, eff_mc = [], []
# rest of code
Your variables can then be shared via self
, and the functions can also be accessed via self
, otherwise staticmethod
keeps access of self
out of the function, which is why you can't call any of the other functions.
Classes are namespaces, and self
allows you to tie variables to the instance-level namespace. By using global
, you are trying to push those variables back to the global namespace to share them around, when really, you already have access to a namespace to share those variables in!
As a simple example:
class A:
# here is the namespace for the *class* A
x = 0 # x is an attribute on the class A, it is accessible on the class and instance level
def __init__(self):
self.y = 4 # y is now explicitly tied to an instance of A, and can be shared between *instance* methods of A
def use_y(self):
# because this is non-static, I have access to instance level
# variables, this is how you share them!
print(self.y)
# I also have access to class-level attributes
print(self.x)
@staticmethod
def use_x():
# I don't have access to self.y, because staticmethod takes that away
try:
print(self.y)
except NameError:
print("Couldn't make this work")
print(A.x) # have to print this as a *class-level* attribute, because self isn't defined here
a = A()
a.use_y()
# 4
# 0
a.use_x()
# Couldn't make this work
# 0
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.