简体   繁体   中英

Python: How to assign function name dynamically in Class

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?

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)

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM