2

How do I fill in the ????

def ensure_finished(iterator):
    try:
        next(iterator)
    except StopIteration:
        return
    else:
        raise RuntimeError


def derived_generator(method):
    def new_method(self, *args, **kwargs):
        x = method(self, *args, **kwargs)
        y = getattr(super(???, self), method.__name__)\
            (*args, **kwargs)

        for a, b in zip(x, y):
            assert a is None and b is None
            yield

        ensure_finished(x)
        ensure_finished(y)

    return new_method
Neil G
  • 32,138
  • 39
  • 156
  • 257
  • @chepner: iterate over the base and superclass iterators simultaneously. – Neil G Sep 18 '14 at 20:28
  • 1
    I would just add this as the use case for your previous question regarding the class which defines a method (just noticed you posted both) rather than asking separately here. – chepner Sep 18 '14 at 20:33
  • why are you not yielding anything? – greschd Oct 23 '14 at 22:19
  • I think @chepner is right. The actual question part of this, "How do I fill in the `???`", is identical to the earlier question, "Given a method, how do I return the class it belongs to", because the answer to that question _is_ the `???` in this question. – abarnert Oct 23 '14 at 22:38
  • @greschd because the point is to synchronize the coroutines. – Neil G Oct 23 '14 at 22:48

1 Answers1

2

EDIT : This does not work for the reasons mentioned in the comments. I'll leave this here so that the next guy trying to answer doesn't do the same thing (until the real answer shows up).

You should use type(self)

Example I simplified your code a bit, but the essence should still be in there

def derived_generator(method):
    def new_method(self, *args, **kwargs):
        x = method(self, *args, **kwargs)
        y = getattr(super(type(self), self), method.__name__)\
            (*args, **kwargs)

        for a, b in zip(y, x):
            yield a, b

    return new_method

class BaseClass(object):
    def iterator(self):
        return [1, 2, 3]

class ChildClass(BaseClass):
    @derived_generator
    def iterator(self):
        return [4, 5, 6]

a = ChildClass()
for x in a.iterator():
    print(x)
greschd
  • 606
  • 8
  • 19
  • 3
    This only works if you're never going to call this method from an instance of a subclass. For example, imagine you create `GrandchildClass` and add a `@derived_generator` override there. So `GrandchildClass.iterator` will super to `ChildClass.iterator`, which will super to `ChildClass.iterator` again, and so on until you hit a recursion error. (This is effectively the same problem that Blckknight pointed out in rioppi's now-deleted answer last month.) – abarnert Oct 23 '14 at 22:24
  • Ahhh, right... didn't think that one through. Should I leave my reply as a bad example? – greschd Oct 25 '14 at 17:56
  • Updated: I found a hacky solution based on https://stackoverflow.com/a/3464154/5426033 Idea is to tweak self.__class__ within ``` def isinvoker(func): """A decorator calling super methods.""" def call_super(self, *args, **kwargs): base_class = type(self).__bases__[0] child_class = type(self) self.__class__ = base_class print(f"decorated locals: {locals()}") fun = base_class.__getattribute__(self, 'f') fun(*args, **kwargs) self.__class__ = child_class return call_super ``` – Shichu Zhu Jun 27 '20 at 07:54