2

I am trying to develop a list(lets called "l") of list of tuple of two natural numbers(excluding 0) such as "a" can be a memeber of "l" if len(a) == len and for every member(lets call p) of "a", p[0] <= max and p[1] <= max

For example poslist_all(max=2,len=1)

[[(1,1)],[(1,2)],[(2,1)],[(2,2)]]

and poslist_all(2,2)

[[(1,1),(1,1)],[(1,1),(1,2)],[(1,1),(2,1)],[(1,1),(2,2)],...,[(2,2),(1,1)],[(2,2),(1,2)],[(2,2),(2,1)],[(2,2),(2,2)]]

So I am trying to make that list an iterator and came up with this code,

class poslist_all:
    def __init__(self,max,len):
        self.max = max
        self.len = len
        self.iposlist = len*[(1,1)]
    def __iter__(self):
        return self
    def __next__(self):
        ml = self.maxlist()
        if ml:
            if ml[0] == 0:
                raise StopIteration
            else:
                toinc = ml[0]-1
                self.inc(ml[0] - 1)
                for i in range(ml[0],self.len-1):
                    self.iposlist[i] = (1,1)
                return self.iposlist
        else:
            self.inc(self.len - 1)
            return self.iposlist
    def maxlist(self):
        return [x for x,y in enumerate(self.iposlist) if y == (self.max,self.max)]
    def inc(pnum):
        if self.iposlist[pnum][1] == self.max:
            return (self.iposlist[pnum][0]+1,1)
        else:
            return (self.iposlist[pnum][0],self.iposlist[pnum][1]+1)

if __name__ == "__main__":
    for ps in poslist_all(2,2):
        print(ps)

but this always returns

Traceback (most recent call last):
  File "./helper.py", line 33, in <module>
    for ps in poslist_all(2,2):
  File "./helper.py", line 22, in __next__
    self.inc(self.len - 1)
TypeError: inc() takes 1 positional argument but 2 were given

Whats causing this error ? How to solve it ? Is there more pythonic way to do this ?

AirTycoon
  • 395
  • 1
  • 3
  • 10
  • 4
    You need `def inc(self, pcnum)`. – rlms Sep 20 '13 at 18:44
  • 1
    Related question: http://stackoverflow.com/q/13652006/510937 – Bakuriu Sep 20 '13 at 19:01
  • 1
    You may also want to read the FAQ [Why must ‘self’ be used explicitly in method definitions and calls?](http://docs.python.org/3/faq/design.html#why-self). Once you understand _why_ Python works this way, it's easier to remember _that_ it works this way. (Or at least it was for me…) – abarnert Sep 20 '13 at 19:28

3 Answers3

11

The class instance is always passed as the first parameter to methods of the class. Try:

def inc(self, pnum):
    if ...:
        return ...
    else:
        return ...
amitparikh
  • 586
  • 5
  • 13
  • 4
    Also, `inc` is not a class method; it's just a method. – Air Sep 20 '13 at 18:47
  • I'd assume he means methods of classes. – rlms Sep 20 '13 at 18:48
  • Better to be precise; someone who doesn't know to pass `self` or `cls` is unlikely to understand these distinctions, but there's no point in setting them up for confusion later on. – Air Sep 20 '13 at 18:53
  • @AirThomas I'm kind of new here... what's the etiquette? Should I edit my own post to correct the mistakes? (Thank you for these valuable comments, btw) – amitparikh Sep 20 '13 at 18:55
  • 4
    @amitparikh: Editing the post should be fine and is probably the most useful thing to do, as new people reading the answer won't need to parse the comments to get the right info out of it. – FatalError Sep 20 '13 at 18:58
4

Others have shown you how to get rid of the error, but I'd like to address the actual problem.

There is indeed a better, more pythonic way to do what you want. The itertools module, and specifically itertools.product() can make this task much simpler.

import itertools as it

def create_possibilities(highest, per_list):
    tuples = it.product(range(1, highest+1), repeat=highest)
    all_possibilities = it.product(tuples, repeat=per_list)
    return all_possibilities

This will return an iterator over iterators(I think that's at least close to the correct terminology).
If you want actual lists, use the list() function as needed.

Also, note that max and len are awful variable names; they shadow python's built-n functions.

stranac
  • 26,638
  • 5
  • 25
  • 30
3

Change:

def inc(pnum):
        if self.iposlist[pnum][1] == self.max:
            return (self.iposlist[pnum][0]+1,1)
        else:
            return (self.iposlist[pnum][0],self.iposlist[pnum][1]+1)

To:

def inc(self, pnum): # methods (in a class) require self
        if self.iposlist[pnum][1] == self.max:
            return (self.iposlist[pnum][0]+1,1)
        else:
            return (self.iposlist[pnum][0],self.iposlist[pnum][1]+1)
Rushy Panchal
  • 16,979
  • 16
  • 61
  • 94
  • 1
    All methods are associated with classes by definition, but in Python, not every method is a [class method](http://docs.python.org/2/library/functions.html#classmethod), which would require `cls` as the first argument (not `self`). Better to be precise and just say "method" here. – Air Sep 20 '13 at 19:03