Python中的原型编程

16 投票
5 回答
5637 浏览
提问于 2025-04-16 09:35

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 个回答

3

简而言之,是的,但比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表达式,或者直接在外面定义一个函数,然后把它的指针加到类对象里。

4

每次你读取一个Python对象的属性时,都会调用一个叫做__getattribute__的方法。你可以重写这个方法,从而完全控制对对象属性的访问。不过,对于你的任务,有一个稍微不同的函数__getattr__可能更合适。与__getattribute__不同的是,__getattr__只有在正常查找属性失败时才会被调用,也就是说,它的调用时机类似于JavaScript中的原型查找。下面是使用示例:

...
def __getattr__(self, name):
    if hasattr(prototype, name)
        return getattr(prototype, name)
    else: 
        raise AttributeError

另外,请注意这个问题,因为里面有关于旧式和新式对象的一些说明。

9

在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

撰写回答