4
\$\begingroup\$

Consider the classAB below that is to be used as a simple customized list ofA objects for lookup operations.

Can this code be improved to avoid instantiatingAB with an empty list[] (i.e., perhaps modify__add__ in some way)?

class A():    def __init__(self, arg):        self.arg = argclass AB():    def __init__(self, list):        self.list = list    def __add__(self, other):        return AB(self.list + [other])ab = AB([])ab += A(1)ab += A(2)
askedFeb 7, 2017 at 21:06
dfernan's user avatar
\$\endgroup\$

3 Answers3

2
\$\begingroup\$

Sure, you can play with the default argument value:

class AB:    def __init__(self, data=None):        self.data = data if data is not None else []    def __add__(self, other):        return AB(self.data + [other.arg])

Other notes:

  • list is a bad variable name as it is shadowing the built-inlist keyword
  • remove redundant parentheses after the class name

Demo:

In [1]: ab = AB()In [2]: ab += A(1)In [3]: ab += A(2)In [4]: print(ab.data)[<__main__.A instance at 0x10afb14d0>, <__main__.A instance at 0x10afa0998>]
answeredFeb 7, 2017 at 21:28
alecxe's user avatar
\$\endgroup\$
4
  • \$\begingroup\$I was looking for other ways to build__add__, but I guess that changing__init__ works too. Thanks for the tips. Note that it is meant forAB(self.data + [other]) (without.arg) in order to maintain a list ofA objects.\$\endgroup\$CommentedFeb 7, 2017 at 21:36
  • \$\begingroup\$@dfernan ah, gotcha, I'll remove the last suggestion. Thanks.\$\endgroup\$CommentedFeb 7, 2017 at 21:36
  • \$\begingroup\$If you just usedata=[] directly instead of beNone indirection does that reuse a single list between__init__ calls? Otherwise that seems cleaner.\$\endgroup\$CommentedFeb 7, 2017 at 23:05
  • 1
    \$\begingroup\$Just got an opportunity to test. Yes, doingdata=[] as a default argument leads to the same list being used for all invocations of__init__. However, this is only an issue if you implement__iadd__.\$\endgroup\$CommentedFeb 8, 2017 at 4:46
2
\$\begingroup\$

I agree that default arguments can (and should) be used for the backing list of your class.

In addition, consider inheriting fromcollections.abc.Sequence and delegating__getitem__ and__len__ to the backing list. (Add other list-like methods as necessary.) This will make sure your class acts as a well-behaved list-like.

In order to qualify as anIterable, you must define__iter__ or__getitem__. In order to qualify as aSequence you must be an Iterable that provides__getitem__ and__len__. It's up to you how much functionality you want to provide, but the Sequence ABC exists for a reason.

answeredFeb 7, 2017 at 23:09
CAD97's user avatar
\$\endgroup\$
1
\$\begingroup\$

My two cents.

class A():    def __init__(self, arg):        self.arg = argclass AB():    def __init__(self):        pass    def __iadd__(self, other):        if not hasattr(self, '_list'):            setattr(self, '_list', [other])        else:            self._list.append(other)        return selfab = AB()ab += A(1)ab += A(3)print(ab._list[1].arg) # Prints 3

We completely avoid the creation of the_list parameter, unless we add anA() object.

Note that we are overriding the+= operator specifically.

answeredFeb 7, 2017 at 21:41
Guimo's user avatar
\$\endgroup\$

You mustlog in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.