简体   繁体   中英

Getting “TypeError: with staticmethid not callable”

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.

Example 1

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

Example 2

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

Example 3

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!)

Explanation

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM