1,105,585 Community Members

if attribute exists: append; else: create

Member Avatar
shayallenhill
Newbie Poster
4 posts since Nov 2012
Reputation Points: 0 [?]
Q&As Helped to Solve: 0 [?]
Skill Endorsements: 0 [?]
 
0
 

Which is smarter?

class HoldAttr(object): pass
a = HoldAttr

b = getattr(a, 'attrname', [])
b.append(1)
setattr(a, 'attrname', b)

# or

try:
    b.a.append(1)
except AttributeError:
    b.a = [1]

... or something else?

Trying to learn.

Member Avatar
HiHe
Posting Whiz
384 posts since Oct 2008
Reputation Points: 160 [?]
Q&As Helped to Solve: 54 [?]
Skill Endorsements: 6 [?]
 
0
 

Something else:

class HoldAttr(object):
    pass

a = HoldAttr()

print(hasattr(a, 'myattr1'))   # False

# create the attribute externally
# unless the class uses __slots__
a.myattr1 = []

print(hasattr(a, 'myattr1'))   # True

# test it
a.myattr1.append(1)

print(a.myattr1)  # [1]
Member Avatar
shayallenhill
Newbie Poster
4 posts since Nov 2012
Reputation Points: 0 [?]
Q&As Helped to Solve: 0 [?]
Skill Endorsements: 0 [?]
 
0
 

That doesn't quite get me there.
Let me give some more context.

import randint

class HoldAttr(object): pass

aname = [HoldAttr() for x in range(10000)]

for i in range(500):
    aindex = random.randint(0, 999)
    try:
        aname[aindex].foundat.append(i)
    except AttributeError:
        aname[aindex].foundat = [i]

Most instances in aname will have no 'foundat' attribute. Some instances in aname may be "found" more than once. Trying not to initialize a 'foundat' attribute for every instance in aname.

Member Avatar
Gribouillis
Posting Maven
3,458 posts since Jul 2008
Reputation Points: 1,140 [?]
Q&As Helped to Solve: 884 [?]
Skill Endorsements: 18 [?]
Moderator
 
0
 

I suggest using a cached property

class HoldAttr(object):

    @cached_property
    def foundat(self):
        return []

    @property
    def was_found(self):
        return "foundat" in self.__dict__

if __name__ == "__main__":
    h = HoldAttr()
    for i in range(3):
        h.foundat.append(i)
    print(h.foundat)
    print(h.was_found)
    h = HoldAttr()
    print(h.was_found)

""" my output -->
[0, 1, 2]
True
False
"""

However, a more classical style makes your code more readable

class HoldAttr(object):
    foundat = None

    def add_found(self, at):
        if self.foundat is None:
            self.foundat = [at]
        else:
            self.foundat.append(at)

    def was_found(self):
        return self.foundat is not None

if __name__ == "__main__":
    h = HoldAttr()
    for i in range(3):
        h.add_found(i)
    print(h.foundat)
    print(h.was_found())
    h = HoldAttr()
    print(h.was_found())

Code with straightforward behavior is better.

Member Avatar
hughesadam_87
Posting Whiz in Training
274 posts since May 2009
Reputation Points: 54 [?]
Q&As Helped to Solve: 13 [?]
Skill Endorsements: 1 [?]
 
1
 

The cached property is definatly the best suggestion. If not using that, I would get in the habit of using try: except in these situations. That is syntactially simple and very common, so others reading your code will be able to deduce your intent from the code.

You
This article has been dead for over three months: Start a new discussion instead
Post:
Start New Discussion
Tags Related to this Article