【发布时间】:2026-02-14 04:10:01
【问题描述】:
我正在使用元类来定义类的只读属性(访问器方法),方法是为类声明的每个字段添加一个只有一个 getter(一个 lambda)的属性。我发现不同的行为取决于我定义 lambda 的位置。如果我在元类的__new__ 方法调用的外部函数中定义getter lambda,而不是直接在元类的__new__ 方法中定义lambda,它会起作用。
def _getter(key):
meth = lambda self : self.__dict__[key]
print "_getter: created lambda %s for key %s" % (meth, key)
return meth
class ReadOnlyAccessors(type):
def __new__(cls, clsName, bases, dict):
for fname in dict.get('_fields',[]):
key = "_%s" % fname
# the way that works
dict[fname] = property(_getter(key))
# the way that doesn't
# meth = lambda self : self.__dict__[key]
# print "ReadOnlyAccessors.__new__: created lambda %s for key %s" % (meth, key)
# dict[fname] = property(meth)
return type.__new__(cls, clsName, bases, dict)
class ROThingy(object):
__metaclass__ = ReadOnlyAccessors
_fields = ("name", "number")
def __init__(self, **initializers):
for fname in self._fields:
self.__dict__[ "_%s" % fname ] = initializers.get(fname, None)
print self.__dict__
if __name__ == "__main__":
rot = ROThingy(name="Fred", number=100)
print "name = %s\nnumber = %d\n" % (rot.name, rot.number)
正如目前所写,执行如下所示:
[slass@zax src]$ python ReadOnlyAccessors.py
_getter: created lambda <function <lambda> at 0x7f652a4d88c0> for key _name
_getter: created lambda <function <lambda> at 0x7f652a4d8a28> for key _number
{'_number': 100, '_name': 'Fred'}
name = Fred
number = 100
注释掉“the way that works”之后的行并取消注释“the way that doesn't”之后的三行会产生这样的结果:
[slass@zax src]$ python ReadOnlyAccessors.py
ReadOnlyAccessors.__new__: created lambda <function <lambda> at 0x7f40f5db1938> for key _name
ReadOnlyAccessors.__new__: created lambda <function <lambda> at 0x7f40f5db1aa0> for key _number
{'_number': 100, '_name': 'Fred'}
name = 100
number = 100
请注意,即使rot.__dict__ 显示_name 是'Fred',name 属性返回的值也是100。
显然,我对创建 lambda 的范围一无所知。
我一直在阅读 Guido 关于访问器元类的文档: https://www.python.org/download/releases/2.2.3/descrintro/#cooperation 以及 Python 数据模型的 Python 文档和这个 http://code.activestate.com/recipes/307969-generating-getset-methods-using-a-metaclass/ 使用元类创建访问器的秘诀, 最后是 * 上我能找到的所有内容,但我就是不明白。
谢谢。
-迈克
【问题讨论】: