Python 局部变量动态函数

Python 局部变量动态函数,python,Python,我试图动态创建一组类属性,但每个动态fget访问器都需要一个唯一的局部变量 以下是一个简化的示例: class Test(object): def __metaclass__(name, bases, dict): for i in range(5): def fget(self, i=i): return i dict['f%d' % i] = property(fget)

我试图动态创建一组类属性,但每个动态fget访问器都需要一个唯一的局部变量

以下是一个简化的示例:

class Test(object):
    def __metaclass__(name, bases, dict):
        for i in range(5):
            def fget(self, i=i):
                return i

            dict['f%d' % i] = property(fget)

        return type(name, bases, dict)

>>> t = Test()
>>> print t.f0, t.f1, t.f2, t.f4
0, 1, 2, 3, 4
为了使每个fget函数都能使用每个正确的“i”值,我必须在创建函数时将其作为关键字参数传递。否则,所有函数都将看到相同的i实例(范围操作生成的最后一个实例)

对我来说,这似乎是一个坏习惯,有更好的方法吗?

“每个动态fget访问器都需要一个唯一的局部变量。”

这说明每个“属性”都是某个类的单独实例

考虑为此使用描述符,这样您就有了一个完整的类,而不是一些拼凑的实例变量


或考虑在<强>策略< /强>设计模式中使用某种变体将这个“唯一的局部变量”委托给这个与属性相关的策略对象。

您可以使用局部变量的闭包,而不是将代码< i>代码>作为默认参数:

class Test(object):
    def __metaclass__(name, bases, dict):
        for i in range(5):
            def asclosure():
               # function to create a new local scope for |ci|
               ci = i
               def fget(self):
                   return ci
               return fget

            dict['f%d' % i] = property(asclosure())

        return type(name, bases, dict)
class Test(object):
    def __metaclass__(name, bases, dict):

        def makeprop( i ):
            # a new namespace where `i` never changes
            def fget(self):
                return i
            return property(fget)

        for i in range(5):
            dict['f%d' % i] = makeprop(i)

        return type(name, bases, dict)

这是可行的,但也似乎非常粗糙,可读性不强。

另一种方法是定义第二个函数,将变量的值捕获为新的局部变量。例如:

def make_prop_that_returns(i):
    return property(lambda self: i)

class Test(object):
    def __metaclass__(name, bases, dict):
        for i in range(5):
            dict['f%d' % i] = make_prop_that_returns(i)

        return type(name, bases, dict)
我不确定我会说这比你的方法更干净,但至少是一种替代方法


你能更清楚(不那么抽象)你想要完成什么吗?定义动态fget可能不是最好的方法。

对于这个简化的示例,我认为您所做的工作非常好(除了有点粗糙)。虽然
i=i
部分可能很难看和棘手,但它是一种相对众所周知的闭包方法。如果你担心有人看不到,请添加评论

然而,如果你在做更复杂的事情,我绝对同意上面s.洛特的观点

另一种可能的办法:

def make_property(i, dict):
    def fget(self):
        return i

    dict['f%d' % i] = property(fget)

class Test(object):
    def __metaclass__(name, bases, dict):
        for i in range(5):
            make_property(i, dict)

        return type(name, bases, dict)

就我个人而言,我觉得这使整个过程更容易理解,因为您将循环的每个迭代分离为自己的函数。

您只需要另一个函数,其中
I
是一个参数:

class Test(object):
    def __metaclass__(name, bases, dict):
        for i in range(5):
            def asclosure():
               # function to create a new local scope for |ci|
               ci = i
               def fget(self):
                   return ci
               return fget

            dict['f%d' % i] = property(asclosure())

        return type(name, bases, dict)
class Test(object):
    def __metaclass__(name, bases, dict):

        def makeprop( i ):
            # a new namespace where `i` never changes
            def fget(self):
                return i
            return property(fget)

        for i in range(5):
            dict['f%d' % i] = makeprop(i)

        return type(name, bases, dict)

公平地说,我认为该声明也可以作为一个指标,表明每个属性也是一个闭包。我觉得这对于这个简单的例子会更好。但是,您可能是对的,这取决于OP的需求有多复杂。代码主要是从解释器中使用的,因此为了简单起见,我希望属性的行为与int完全相同(例如,读取值不需要强制转换)。实际上,该属性也有一个fset,您可以将其视为操纵一个备份存储,如数据库,或者在我的例子中是嵌入式硬件寄存器(i是地址偏移量)。添加一条注释以指示我正在创建闭包,这会让我感觉更好,而不会增加实现的复杂性。;-)