Получение "TypeError: с staticmethid не вызывается" - PullRequest
0 голосов
/ 22 мая 2019

Я получаю сообщение об ошибке TypeError: объект «staticmethod» не вызывается. По сути, вы вводите карту и, учитывая, что вы предоставляете пару чисел с плавающей запятой (pt, eta), код должен возвращать значение Y бина, в которое попадают конкретные значения.

Я пробовал связанную ветку (как возможные дубликаты), но, похоже, не получил ответ, который искал.

Конечно, если есть какие-либо рекомендации по улучшению кода, это, конечно, приветствуется.

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

Ответы [ 2 ]

2 голосов
/ 22 мая 2019

Чтобы немного прокрутить ответ @ Felipe, не делая все ваши методы static, вы можете исключить необходимость в объявлениях global для совместного использования переменных, поскольку в любом случае это то, что вы делаете:

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

Ваши переменные затем могут быть переданы через self, а функции также доступны через self, в противном случае staticmethod удерживает доступ к self вне функции, поэтому вы не можете вызывать любые других функций.

Классы являются пространствами имен, а self позволяет связывать переменные с пространством имен уровня экземпляра. Используя global, вы пытаетесь переместить эти переменные обратно в глобальное пространство имен, чтобы обмениваться ими, когда на самом деле у вас уже есть доступ к пространству имен, в котором эти переменные доступны!

В качестве простого примера:

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
2 голосов
/ 22 мая 2019

Некоторые примеры, которые могут быть полезны, чтобы увидеть, что происходит.

Пример 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!"))

Выходы

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

Пример 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!"))

выход

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

Пример 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!"))

выход

global_function(test)
random_function(Input!)

Объяснение

Короче говоря, @staticmethod не может получить доступ к функциям в своем классе this (определен ли он с помощью this или global) и вместо этого должен инициализировать новый и независимый класс для вызова функции внутри класса, в котором он находится. в (пример 3). Как упомянул @ C.Nivs, возможно, вам стоит просто не использовать класс.

...