在Python中确切地获得你所要求的内容是棘手的 - 这是因为,当你执行“instance.x.method”时,Python首先从“instance”检索属性“x”,然后尝试在“x”对象本身中查找“method”作为属性(与最初引用“x”的“instance”无关,可能可以从“方法”内部检索到“x” - 但对于帧内省来说)。
__setattr__ 方法,在实例上设置每个属性时,它实际上会创建该属性的动态子类 - 这将使新对象上的所需方法可用。缺点是,并非所有类型的对象都可以成为子类,并且并非所有子类对象都会完全像它们的父类一样行为(例如,如果“x”是一个函数)。但对于大多数情况来说,它都能工作。
class Base(object):
def __setattr__(self, name, attr):
type_ = type(attr)
new_dict = {}
for meth_name in dir(self.__class__):
function = getattr(self.__class__, meth_name)
if not callable(function) or meth_name in new_dict or meth_name.startswith("_"):
continue
def pinner(f):
def auto_meth(se, *args, **kw):
return f(se._container, se, *args, **kw)
return auto_meth
new_dict[meth_name] = pinner(function)
new_type = type(type_.__name__, (type_,), new_dict)
try:
attr.__class__ = new_type
except TypeError:
attr = new_type(attr)
attr._container = self
super(Base, self).__setattr__(name, attr)
class oObject(Base):
def __init__(self, x = 0, y = 0, z = 0):
self.x = x
self.y = y
self.z = z
def asString(self, attr):
return str(attr)
在交互式部分加载这些内容后:
>>> v = oObject(1,2,3)
>>> v.x.asString()
'1'
>>> v.w = [1,2,3]
>>> v.w.append(3)
>>> v.w.asString()
'[1, 2, 3, 4]'
>>>
如你所见,这可以通过普通的类继承来实现,不需要元类。
对于任何参数类型,另一种更可靠的方法是使用另一个分隔符来表示属性名和方法 - 然后你可以在基类上编写一个更简单的`__getattribute__`方法,动态地检查请求的方法并调用相应的属性。这种方法不需要动态子类化,而且要简单两个数量级。代价是你需要像`vector.x__asString`这样的写法,而不是使用点分隔符。实际上,这就是Python中经过验证的SQLAlchemy ORM采用的方法。
class Base(object):
separator = "__"
def __getattr__(self, attr_name):
if self.__class__.separator in attr_name:
attr_name, method_name = attr_name.split(self.__class__.separator, 1)
method = getattr(self, method_name)
return method(getattr(self, attr_name))
raise AttributeError
现在:
>>> class oObject(Base):
... def __init__(self, x = 0, y = 0, z = 0):
... self.x = x
... self.y = y
... self.z = z
...
... def asString(self, attr):
... return str(attr)
...
>>>
>>>
>>> v = oObject(1,2,3)
>>> v.x__asString
'1'
如果您想要传递更多参数给被调用的方法,那么需要编写更多的代码,但我认为这已经足够让您了解思路了。
int
添加自定义方法吗?如果这只是一个例子,而你真正指的是对象,那么x
可能是一个带有asString
方法的自定义对象。 - jdivector.asString('x')
。 - Joel Cornett