简体   繁体   中英

A python function that return a list of function with a for loop

I am trying to implement a function (make_q) that returns a list of functions(Q) that are generated using the argument that make_q gets (P). Q is a variable dependent to n(=len(P)) and making the Q functions are similar, so it can be done in a for loop but here is the catch if I name the function in the loop, they will all have the same address so I only get the last Q, Is there to bypass this? Here is my code,

 def make_q(self):
        Temp_P=[p for p in self.P]
        Q=()
        for i in range(self.n-1):
            p=min(Temp_P)
            q=max(Temp_P)
            index_p=Temp_P.index(p)
            index_q=Temp_P.index(q)
            
            def tempQ():
                condition=random.random()
                if condition<=(p*self.n):
                    return index_p
                else:
                    return index_q
            Temp_Q=list(Q)
            Temp_Q.append(tempQ)
            Q=tuple(Temp_Q)
            q-=(1-p*self.n)/self.n
            Temp_P[index_q]=q
            Temp_P.pop(index_p)

        return Q
test.Q

(<function __main__.Test.make_q.<locals>.tempQ()>,
 <function __main__.Test.make_q.<locals>.tempQ()>,
 <function __main__.Test.make_q.<locals>.tempQ()>,
 <function __main__.Test.make_q.<locals>.tempQ()>,
 <function __main__.Test.make_q.<locals>.tempQ()>)

I also tried to make them a tuple so they have different addresses but it didn't work. Is there a way to name functions(tempQ) dynamic like tempQi

jasonharper's observation and solution in comments is correct(and should be the accepted answer). But since you asked about metaclasses, I am posting this anyway.

In python, each class is a type , with "name", "bases" (base classes) and "attrs"(all members of a class). Essentially, a metaclass defines a behaviour of a class, you can read more about it at https://www.python-course.eu/python3_metaclasses.php and various other online tutorials.

The __new__ method runs when a class is set up. Note the usage of attrs where your class member self.n is accessed by attrs['n'] (as attrs is a dict of all class members). I am defining functions tempQ_0, tempQ_1... dynamically. As you can see, we can also add docstrings to this dynamically defined class members.

import random


class MyMetaClass(type):

    def __new__(cls, name, bases, attrs):
        Temp_P = [p for p in attrs['P']]
        for i in range(attrs['n'] - 1):
            p = min(Temp_P)
            q = max(Temp_P)
            index_p = Temp_P.index(p)
            index_q = Temp_P.index(q)

            def fget(self, index_p=index_p, index_q=index_q):  # this is an unbound method
                condition = random.random()
                return index_p if condition <= (p * self.n) else index_q

            attrs['tempQ_{}'.format(i)] = property(fget, doc="""
            This function returns {} or {} randomly""".format(index_p, index_q))

            q -= (1 - p * attrs['n']) / attrs['n']
            Temp_P[index_q] = q
            Temp_P.pop(index_p)

        return super(MyMetaClass, cls).__new__(cls, name, bases, attrs)


# PY2
# class MyClass(object):
#     __metaclass__ = MyMetaClass
#     n = 3
#     P = [3, 6, 8]


# PY3
class MyClass(metaclass=MyMetaClass):
    n = 3
    P = [3, 6, 8]

# or use with_metaclass from future.utils for both Py2 and Py3

# print(dir(MyClass))
print(MyClass.tempQ_0, MyClass.tempQ_1)

output

<property object at 0x10e5fbd18> <property object at 0x10eaad0e8>

So your list of functions is [MyClass.tempQ_0, MyClass.tempQ_1]

Please try via formatted strings, for eg: "function_{}.format(name)" also, how do you want your output to look like?

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