-1

I experienced an "AttributeError" with the following Python code:

Def SomeFunc(Self):
    ....
    setattr(Self, "_Some_Attribute", Data)
    ....
    if hasattr(Self, "_Some_Attribute"):
        delattr(Self, "_Some_Attribute")
    ....

And the AttributeError was raise on the delattr line immediately after the hasattr test was positive. The panic was pretty rare. I would say once in few hundreds times.

SomeFunc() may be called from multiple threads. Is it possible that another thread get in between the hasattr and delattr to remove the "_Some_Attribute" after the first thread test hasattr positive?

Trendy
  • 26
  • 4
  • 2
    Please post actual code. – Daniel Roseman Dec 17 '15 at 20:45
  • Also, please check for duplicate http://stackoverflow.com/questions/1120927/which-is-better-in-python-del-or-delattr – mrDinkelman Dec 17 '15 at 20:53
  • `hasattr` and `delattr` are all lowercase. Voting to close as typo. – user2357112 Dec 17 '15 at 20:54
  • Sorry about the typo. The actual code is: if hasattr(Self, "_Some_Attribute"): delattr(Self, "_Some_Attribute") – Trendy Dec 17 '15 at 23:32
  • 1
    In the other answer you mentioned _" The panic was pretty rare. I would say once in few hundreds times. "_ Is this a multithreaded app? In your real code, is there more processing between the `hasattr` and `delattr` that could have logic errors? As stands, your problem is not reproducable. – tdelaney Dec 18 '15 at 00:01
  • Yes, it is multi-threaded. And definitely no processing in between hasattr and delattr on a single thread. The code is like that. Is it possible that another thread get in between the hasattr and delattr to remove the "_Some_Attribute"? Anyone who know GIL enough to tell if that is possible? Thank you. – Trendy Dec 18 '15 at 00:05

2 Answers2

1

When looking up an attribute on an object, python first looks at self and then at the class namespace. So, instance variables and class variables both pass the hasattr test. Such is not the case when deleting attributes. Class variables will not be deleted.

class C(object):

    classvar = 'foo'

    def __init__(self):
        self.instancevar = 'bar'

c = C()
print('hasattr sees instance and class vars', hasattr(c, 'classvar'), hasattr(c, 'instancevar'))
print('delete instance is fine')
delattr(c, 'instancevar')
print('but classvar is not')
delattr(c, 'classvar')

When run, you get your error

hasattr sees instance and class vars True True
delete instance is fine
but classvar is not
Traceback (most recent call last):
  File "u.py", line 13, in <module>
    delattr(c, 'classvar')
AttributeError: classvar

EDIT

With the revised code, I can no longer reproduce. My test case below works without error.

class C(object):
    def test(self):
        setattr(self, '_foo', 'bar')
        if hasattr(self, '_foo'):
            delattr(self, '_foo')
C().test()
print("Test Passed")
tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • Thank you. This is really good to know. However, I don't that is my case. Please see the actual code that I posted. – Trendy Dec 17 '15 at 23:47
0

It is not clear why the problem occurs in your case. The code snippets you gave are not enough for a conclusive analysis.

However, there is a solution nevertheless!

Instead of:

if hasattr(Self, "_Some_Attribute"):
    delattr(Self, "_Some_Attribute")

Do this:

try:
    delattr(Self, "_Some_Attribute")
except AttributeError:
    # here you choose what you want to do, some options:
    pass
    print 'delattr failed' if hasattr(Self, "_Some_Attribute") else 'ok'
    assert not hasattr(Self, "_Some_Attribute")

It is easier to ask for forgiveness than permission.

zvone
  • 18,045
  • 3
  • 49
  • 77