2

I constructed a class:

class Foo (object):
      def __init__(self,List):
          self.List=List
      @property
      def numbers(self):
          L=[]
          for i in self.List:
              if i.isdigit():
                 L.append(i)
          return L
      @property
      def letters(self):
          L=[]
          for i in self.List:
              if i.isalpha():
                 L.append(i)
          return L

>>> inst=Foo(['12','ae','45','bb'])
>>> inst.letters
['ae', 'bb']
>>> inst.numbers
['12', '45']

How can I add attributes so I could do inst.numbers.odd that would return ['45']?

2 Answers 2

3

Your numbers property returns a list, so a numbers.odd won't work.

However, you could follow a workflow like:

  • define a small class Numbers, that would define two properties even and odd For example, Numbers could take a list as argument of its __init__, the even property would return only the even number of this list [i for i in List if int(i)%2 == 0] (and odd the odd ones)...

  • create an instance of Numbers in your Foo.numbers property (using your Foo.List to initialize it) and return this instance...

Your Numbers class could directly subclass the builtin list class, as suggested. You could also define it like

class Numbers(object):
    def __init__(self,L):
        self.L = L
    @property
    def even(self):
        return [i for i in self.L if not int(i)%2]
    def __repr__(self):
        return repr(self.L)

Here, we returning the representation of Numbers as the representation of its L attribute (a list). Fine and dandy until you want to append something to a Numbers instance, for example: you would have to define a Numb.append method... It might be easier to stick with making Numbers a subclass of list:

 class Numbers(list):
    @property
    def even(self):
        ...

Edited: corrected the // by a %, because I went too fast and wasn't careful enough

Sign up to request clarification or add additional context in comments.

2 Comments

yes,but how can i get inst.numbers still return ['12', '45'] then. i couldnt figure it out...
Your even test should be not int(i)%2. (not int(57)//2) is (not int(56)//2) should return True.
2

Here's a silly example:

class mylst(list):
    @property
    def odd(self):
        return [ i for i in self if int(i)%2 == 1 ]

class Foo(object):
    def __init__(self,lst):
        self.lst = list(lst)

    @property
    def numbers(self):
        return mylst( i for i in self.lst if i.isdigit() )

a = Foo(["1","2","3","ab","cd"])
print(a.numbers)
print(a.numbers.odd)

Basically, we just subclass list and add a property odd which returns another list. Since our structure is a subclass of list, it is virtually indistinguishable from the real thing (Horray duck typing!). mylst.odd could even return a new instance of mylst if you wanted to be able to filter it again (e.g. a.numbers.odd.in_fibinocci )

4 Comments

I can think of some horrible ways this could be achieved, but inheriting from list is elegant +1
@JonClements -- I'm pretty sure you could do something like this using descriptors, but I've never had occasion to use them. And inheriting from python builtin types is easy as pi!
Yep - descriptors can be used (and if it were more complex, could well be a practical answer) - but in this use-case, it's overkill, and this answer solves the OPs problem nicely ;)
@ Jon Clements - you are right, it is a silly example but I was trying to learn smth at more abstract level. I will try to dig into descriptors then...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.