2

I have an question about how to assign function name dynamically in Class.

For example:

If a class wants to be used for "for...in" loop, similar to a list
or a tuple, you must implement an __iter__ () method

python2.x will use __iter__() and next(),
python3.x need to use __iter__() and __next__()

Code:

The sample is get fibonacci numbers within 10

class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1

    def __iter__(self):
        return self

    if sys.version_info[0] == 2:
        iter_n = 'next'  #if python version is 2.x
    else:
        iter_n = '__next__'  #if python version is 3.x

    print('iter_n value is ', iter_n)

    #for py2 I want to replace "iter_n" to "next" dynamically
    #for py3 I want to replace "iter_n" to "__next__" dynamically

    def iter_n(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > 10:
            raise StopIteration();
        return self.a

Test:

for i in Fib():
    print(i)

Expected Result should be:

('iter_n value is ', 'next')
1
1
2
3
5
8

Actual Result:

('iter_n value is ', 'next')
Traceback (most recent call last):
......
TypeError: iter() returned non-iterator of type 'Fib'

Code will be able to get the right results

  • for python 2, if I replace def iter_n(self) to def next(self)
  • for python 3, if I replace def iter_n(self) to def __next__(self)

Question:

How should I put next or __next__ to iter_n dynamically?

3 Answers 3

5

I don't think there's a need to create this method dynamically. Just implement both; clearer and easier. And your code will be Python 2/3 compatible without needing an if-statement.

class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1

    def __iter__(self):
        return self

    def iter_n(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > 10:
            raise StopIteration();
        return self.a

    def next(self):
        return self.iter_n()

    def __next__(self):
        return self.iter_n()


if __name__ == '__main__':
    for i in Fib():
        print(i)
Sign up to request clarification or add additional context in comments.

Comments

1

Agreed that just implementing both is probably best, but something like this seems to do what you intend:

    def iter_n(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > 10:
            raise StopIteration();
        return self.a

    if sys.version_info[0] == 2:
        next = iter_n
    else:
        __next__ = iter_n
    del iter_n

The above removes the original iter_n once it is assigned to the appropriate attribute. Presumably if you're going through this effort you would want to do this cleanup, too.

Comments

-1

In python there is the way to call a function ,method ,get any element by using getattr(from,'name of attribute to call').

below is the sample example of this:

class A():
    def s(self):
            print "s fun"
    def d(self):
            print "a fun"
    def run(self):
            print "in run"

def main():
    print "in main"
    classA = A()
    func_list = ['s','d','run']
    for i in func_list:
            func = getattr(classA,i)
            func()

main()

Try to use this to call function dynamically.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.