histos = dict()
for key in list:
obj = file.Get(key)
if not key in histos:
histos[key] = obj.Clone()
else
histos[key].Add(obj)
Add() is a function of TH1, however I get the following error if the object is retrieved from a python dict():
Traceback (most recent call last):
File "./script.py", line 35, in <module>
histos[key].Add(obj)
AttributeError: 'PyROOT_NoneType' object has no attribute 'Add'
How can I typecast ROOT objects retrieved from dict()
The problem is not that you need to cast the object, the problem is that file.Get will return a None type object (technically a PyROOT_NoneType object, as mentioned in the error message) if it can not find the key in the file, instead of raising an exception.
You should add a check against this, like so:
histos = dict()
for key in list:
obj = file.Get(key)
if not obj:
print("Could not find", key, "in", file)
continue
if not key in histos:
histos[key] = obj.Clone()
else:
histos[key].Add(obj)
Sorry, I take my previous reply back. When retrieveing a non-existing object, a TObject with a nullptr is returned:
# Create an empty new file
>>> f = ROOT.TFile("foo.root", "recreate")
# Try to retrieve a non-existing object from it
>>> f.Get("bar")
<ROOT.TObject object at 0x(nil)>
# Try to clone it
>>> f.Get("bar").Clone()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ReferenceError: attempt to access a null-pointer
While the code I posted guards against this, this is not your problem here.
In other words, what is potentially wrong with this code? I basically want to hadd many root files applying a different scaling to different files:
fOut = ROOT.TFile.Open("MC_sum.root", "RECREATE")
histos = dict()
for sample in samplesList:
fIn = ROOT.TFile.Open(sample + '.root')
for tkey in fIn.GetListOfKeys():
key = tkey.GetName()
obj = fIn.Get(key)
obj.Scale(3)
obj.SetDirectory(0)
if not key in histos:
histos[key] = obj.Clone()
else
histos[key].Add(obj)
fIn.Close()
for key in histos:
fOut.cd()
histos[key].Write()
fOut.Close()
You should really mark the code as code. If you are posting from a browser, there is the </> sign in the toolbar. If you are posting from email or similar, wrap your code with triple back-quotes (```). This way the indentation, which is quite important in Python, is conserved.
I see two unrelated problems in your code (which looks much better now).
You are missing a : in the else branch.
You should only close the fOut file after your final for loop.
However, this is not your problem…
When trying your code on an example file I have lying around, it seems to work. The histograms still exist, even after closing the corresponding input file.
What you could try to do is put the files in a list of open files and close them in a separate loop:
files = [ROOT.TFile.Open(sample + '.root') for sample in samplesList]
for fIn in files:
# Get histograms
for tkey in fIn.GetListOfKeys():
key = tkey.GetName()
obj = fIn.Get(key)
obj.Scale(3)
if not key in histos:
histos[key] = obj.Clone()
else
histos[key].Add(obj)
for fIn in files:
fIn.Close()
By the way I don’t see why you have the obj.SetDirectory(0) there, so I removed it in the code above.
I was also able to replicate the core of the problem:
>>> f = ROOT.TFile("bla.root")
>>> h2 = f.Get("h2")
>>> d = {}
>>> d['h2'] = h2.Clone()
>>> d
{'h2': <ROOT.TH1D object ("h2") at 0x55ca3b5766d0>}
>>> f.Close()
>>> d
{'h2': None}