Python 局部变量动态函数
我试图动态创建一组类属性,但每个动态fget访问器都需要一个唯一的局部变量 以下是一个简化的示例: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)
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是地址偏移量)。添加一条注释以指示我正在创建闭包,这会让我感觉更好,而不会增加实现的复杂性。;-)