user3163030
user3163030

Reputation: 343

yield in staticmethod tied to instance?

I wrote this in python 3 and am curious why the generator, produced under the @staticmethod decorator by the yield statement points to the same generator object per instance, yet produces instance specific results?

class Note:

    def __init__(self):
        pass

    @staticmethod
    def gen():
        x = 0
        while True:
            x +=1
            yield x

    def id(self):
        print(self.gen)
        a = self.gen
        print(next(a()))


n1 = Note()
n2 = Note()
print(n2.id(),n1.id())

This outputs:

<function Note.gen at 0x6ffffd7dd08>
1
<function Note.gen at 0x6ffffd7dd08>
1
None None

Upvotes: 1

Views: 1037

Answers (2)

zvone
zvone

Reputation: 19372

No, it does not. Try with one instance, the same will happen:

n1 = Note()
print(n1.id(), n1.id())

It creates one generator per call to id(), i.e. per call to gen().

EDIT (explanation of generators)

I'll try to explain with this example:

>>> def gen():
...  yield 1
...  yield 2
...  yield 3
...  yield 4
...
>>>
>>> gen
<function gen at 0x00000000029119C8>
>>> gen
<function gen at 0x00000000029119C8>
>>> g1 = gen()
>>> g2 = gen()
>>> g1
<generator object gen at 0x00000000025515A0>
>>> g2
<generator object gen at 0x000000000258B870>
>>> next(g1)
1
>>> next(g1)
2
>>> next(g2)
1
>>> next(g2)
2
>>> next(g1)
3
>>>

As you can see above, gen is not a generator. It is a function. The return value of that function is a generator. So, when I printed gen multiple times, I got the same function. However, when I called it twice, I got two generators g1 and g2. Each of them holds its state, as you can see in calls to next.

EDIT 2 (original example fixed)

BTW, I guess in your code you were trying to do this:

import itertools

class Note:
    gen = itertools.count(1)

    def __init__(self):
        self.id = next(self.gen)

n1 = Note()
n2 = Note()
print(n2.id, n1.id)

EDIT 3 (objects in the same address)

Try this example:

class A:
    def __init__(self, name):
        self.name = name
        print('Created a new A %s with name %s' % (self, name))

def f(name):
    # create a new object A
    a = A(name)
    # a not stored anywhere, so Python will delete it now

f('one')
f('two')
f('three')

In my test, it outputs:

Created a new A <__main__.A object at 0x00000000029C0CF8> with name one
Created a new A <__main__.A object at 0x00000000029C0CF8> with name two
Created a new A <__main__.A object at 0x00000000029C0CF8> with name three

Upvotes: 1

Martijn Pieters
Martijn Pieters

Reputation: 1124000

You created two generators; each call to Note.gen() produces a new generator object. The same would happen if you made these functions outside the class.

Upvotes: 0

Related Questions