Python中的原型编程
JavaScript的对象是基于原型的模型。不过,这门语言非常灵活,可以用几行代码写出一些函数,来替代其他类型的结构。比如,我们可以创建一个 class
函数,模拟标准类的行为,包括继承或私有成员。或者,我们可以通过编写一个 curry
函数来模仿函数工具,这个函数会接收一个函数和它的一些参数,然后返回一个部分应用的函数。
我在想,是否可以反过来,在更传统的语言中模仿原型方法。特别是我在考虑,是否可以在Python中模仿原型,但由于缺乏对匿名函数的支持(比lambda更广泛),我有些卡住了。
在基于类的语言中,特别是在Python中,是否可以写一些函数来模仿原型?
编辑 让我给出一些如何实现这种东西的例子(但我并不能完全做到)。
首先,最接近JavaScript对象的东西是Python字典。所以我们可以有简单的对象,比如
foo = {
'bar': 1,
'foobar': 2
}
当然,我们想要添加方法,只要这个方法适合放在lambda中,这并不是问题。
foo = {
'bar': 1,
'foobar': 2,
'method': lambda x: x**2
}
所以现在我们可以调用,比如说
foo['method'](2)
>>> 4
现在如果我们有任意函数作为方法,我们可以这样继续。首先,我们需要让 foo
内部的函数能够访问到 foo
本身;否则它们只是普通函数,而不是方法。
我想可以通过对 foo
应用一个 makeObject
函数来实现这一点,这个函数会遍历 foo
的值,每当找到一个可调用的值时,就修改它的 __call__
属性,使其将 foo
作为第一个参数传递。
到这个阶段,我们就会有独立的对象,可以在不创建类的情况下声明。
然后我们需要能够给 foo
一个原型,这个原型可以作为 makeObject
函数的第二个参数传递。这个函数应该修改 foo.__getattr__
和 foo.__setattr__
,如下:每当在 foo
中找不到属性时,就应该在 foo.prototype
中查找。
所以,我想我能够实现这个,除了有一点:我想不出任何方法来声明比lambda更复杂的方法,除了提前声明它们并将它们附加到我的对象上。问题在于缺乏匿名函数。我在这里问是因为也许某个Python高手能找到一些聪明的方法来解决这个问题。
5 个回答
简而言之,是的,但比JS
要复杂一些。
来自Python中的类的编程:
>>> class ChattyType(type):
... def __new__(cls, name, bases, dct):
... print "Allocating memory for class", name
... return type.__new__(cls, name, bases, dct)
... def __init__(cls, name, bases, dct):
... print "Init'ing (configuring) class", name
... super(ChattyType, cls).__init__(name, bases, dct)
...
>>> X = ChattyType('X',(),{'foo':lambda self:'foo'})
Allocating memory for class X
Init'ing (configuring) class X
>>> X, X().foo()
(<class '__main__.X'>, 'foo')
还可以查看Python中的类是什么。
编辑:查看基于原型的面向对象,这是你能找到的最接近的东西,但最终还是得用一个lambda表达式,或者直接在外面定义一个函数,然后把它的指针加到类对象里。
每次你读取一个Python对象的属性时,都会调用一个叫做__getattribute__
的方法。你可以重写这个方法,从而完全控制对对象属性的访问。不过,对于你的任务,有一个稍微不同的函数__getattr__
可能更合适。与__getattribute__
不同的是,__getattr__
只有在正常查找属性失败时才会被调用,也就是说,它的调用时机类似于JavaScript中的原型查找。下面是使用示例:
...
def __getattr__(self, name):
if hasattr(prototype, name)
return getattr(prototype, name)
else:
raise AttributeError
另外,请注意这个问题,因为里面有关于旧式和新式对象的一些说明。
在Python中,这比在JavaScript中简单多了。你的JavaScript代码可以用下面的Python代码替代:
>>> class Foo(object):
... pass
>>> foo = Foo()
>>> foo.bar = 1
>>> foo.foobar = 2
然后你还可以动态地添加方法。
>>> foo.method = lambda x: x**2
>>> foo.method(2)
4
对于比简单函数更复杂的方法,你可以把它们声明为函数,这样它们就能访问到foo本身,完全没有问题:
>>> def mymethod(self, bar, foobar):
... self.bar = bar
... self.foobar = foobar
>>> foo.mymethod = mymethod
>>> foo.mymethod(1,2)
>>> foo.bar
1
>>> foo.foobar
2
或者说:
>>> mymethod(foo, 3, 4)
>>> foo.bar
3
>>> foo.foobar
4
其实是一样的。
所以你看,在Python中实现你例子中的功能几乎简单得让人觉得不可思议。问题是为什么。:) 我的意思是,这样做会更好:
>>> class Foo(object):
... def __init__(self, bar, foobar):
... self.bar = bar
... self.foobar = foobar
... def method(self, x):
... return x**2