16

Javascript uses a prototype-based model for its objects. Nevertheless, the language is very flexible, and it is easy to write in a few lines functions which replace other kind on constructs. For instance, one can make a class function, emulating the standard class behaviour, including inheritance or private members. Or one can mimcìic functional tools by writing, for instance, a curry function which will take a function and some of its arguments and return the partially applied function.

I was wondering whether it is possible to do the reverse and imitate the prototypal method in more classical languages. In particular I have been thinking a bit whether it is possible to imitate prototypes in Python, but the lack of support for anonymous functions (more general than lambdas) leaves me stuck.

Is it possible to write some functions to mimic propotypes in class-based languages, in particular in Python?

EDIT Let me give some example of how one could go implementing such a thing (but I'm not really able to do it all).

First, the thing which most closely resembles Javascript objects is a Python dictionary. So we could have simple objects like

foo = {
    'bar': 1,
    'foobar': 2
}

Of course we want to add method, and this is not a problem as long as the method fits in a lambda

foo = {
    'bar': 1,
    'foobar': 2,
    'method': lambda x: x**2
}

So now we can call for instance

foo['method'](2)
>>> 4

Now if we had arbitrary functions as methods we could go on like this. First we need the functions inside foo to have access to foo itself; otherwise they are just ordinary functions and not methods.

I guess one could do this by applying a makeObject function to foo, which loops through foo values and, whenever finds a value that is callable, modifies its __call__ attribute to pass foo as its first argument.

At this stage we would have self standing objects, which can be declared without the need of creating classes.

Then we need to be able to give foo a prototype, which can be passed as a second argument of the makeObject function. The function should modify foo.__getattr__ and foo.__setattr__ as follows: whenever the attribute is not found in foo, it should be searched in foo.prototype.

So, I think I would be able to implement this, expect for one thing: I cannot think any ways to declare methods more complicated than lambdas, except for declaring them beforehand and attaching them to my object. The problem is the lack of anonymous functions. I asked here because maybe some Python guru could find some clever way to circumvent this.

Daniel Mahler
  • 7,653
  • 5
  • 51
  • 90
Andrea
  • 20,253
  • 23
  • 114
  • 183
  • Can you give an example of what you want to do, and how would "prototypal" programming look in Python in your vision? – Rosh Oxymoron Jan 07 '11 at 19:23
  • I don't know exactly how it would look. But for an example of the reverse (how classical OOP looks in Javascript) you can see for instance http://ejohn.org/blog/simple-javascript-inheritance/ – Andrea Jan 07 '11 at 19:36
  • 3
    currying has nothing to do with prototypes or classes. Python's classes are pretty equivalent to prototypes already, since you can freely change them or subclass them at runtime. – Jochen Ritzel Jan 07 '11 at 19:48
  • I never claimed that currying has anything to do with classes. I just said that Javascript can emulate patterns typical of the usual OOP (like classes) or patters typical of functional languages (like currying) – Andrea Jan 07 '11 at 19:54
  • "At this stage we would have self standing objects, which can be declared without the need of creating classes." Why? It hasn't saved much more than a couple of keywords. What would be point be? – S.Lott Jan 07 '11 at 20:03
  • In prototypal languages you don't create classes to instance object. You just create the instances themselves and possibly clone and modify them. Inheritance is done by attaching a prototype. The point of my question is whether is it possible to simulate this style of coding in Python. The reverse (simulating classes in prototype languages) is definitely possible, so why not? ;-) – Andrea Jan 07 '11 at 20:06
  • @Andrea - OneOfOne added a LtU link to his post that has a comment that includes a Python impl of a prototyping object. I think that covers it in the simplest cases except for dealing with bound methods. I'm not familiar with Javascript - are there bound methods that implicitly work on the object's state? – Jeremy Brown Jan 07 '11 at 20:40
  • 4
    Yes, possible. But just as JS programmers (the guys who use a prototype-OO and somewhat functional language, not the code monkeys who copypaste terrible code for their shiny <blink>ing website) will despise you for emulating classes just for the sake of not using prototypes, Python programmers won't see any sense in emulating prototypes unless except in certain cases where they are worth it. Don't work against the language. –  Jan 07 '11 at 20:40
  • Of course (should have I mentioned this?) I'm not working against the language. I would never use it in real projects. I'm just experimenting with what can be done. – Andrea Jan 07 '11 at 20:45
  • 3
    Why would you want to eschew a traditional model of programming that provides built-in support for inheritance, in order to emulate one where everyone has a competing method of, in turn, emulating inheritance, each one subtly broken? – Karl Knechtel Jan 07 '11 at 20:49
  • 6
    First, prototypal inheritance is not broken. Second - again - why not? I'm just experimenting with Python capabilities. – Andrea Jan 07 '11 at 21:13
  • As a matter of fact, one _can_ imple,ment anything as a lambda - it will ust becme _big_ and obuscated-grade hard to read. If one htinks better, "inline" anonymous functions inherit a lot of this obfuscation as well .. oe is much better writting the full functions where they are due. – jsbueno Jan 08 '11 at 02:41
  • @jsbueno This is interesting (although not very practical). Do you have a proof of this claim? It is not entirely clear to me that one can inline functions with arbitrarily complex logic and side effects. – Andrea Jan 08 '11 at 13:45

5 Answers5

9

It's much easier in Python than in JS. Your JS code could be replaced with this in Python:

>>> class Foo(object):
...      pass

>>> foo = Foo()
>>> foo.bar = 1
>>> foo.foobar = 2

Then you can add methods dynamically as well

>>> foo.method = lambda x: x**2
>>> foo.method(2)
4

For methods more complicated than lambdas, you declare them as functions, and they will have access to foo itself, no problems:

>>> def mymethod(self, bar, foobar):
...     self.bar = bar
...     self.foobar = foobar
>>> foo.mymethod = mymethod
>>> foo.mymethod(1,2)
>>> foo.bar
1
>>> foo.foobar
2

Or for that matter:

>>> mymethod(foo, 3, 4)
>>> foo.bar
3
>>> foo.foobar
4

Same thing.

So as you see, doing what your example is in Python is almost ridiculously simple. The question is why. :) I mean, this would be better:

>>> class Foo(object):
...     def __init__(self, bar, foobar):
...         self.bar = bar
...         self.foobar = foobar
...     def method(self, x):
...         return x**2
Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251
  • 8
    I don't think that's quite enough - there is an attribute resolution order that works its way up the prototype hierarchy. Another thing - I'm not sure if Javascript has implicitly bound methods that operates on the object's internal state. If it does, then a little more magic would be required for dynamically adding methods. – Jeremy Brown Jan 07 '11 at 20:33
  • @Jeremy Brown: Yeah, but the question was if you could do it in *Python* and it does have bounding (albeit explicit), so it works. None of the examples in the question use any prototype hierarchy, although this is obviously also possible, but you might want to use metclasses then. – Lennart Regebro Jan 07 '11 at 20:37
  • Actually, if you read the question, I DO mention the prototype hierarchy, and I even say how one could go about implementing it. The reason why I stopped making examples is that before that point I assume one can give the object arbitrary functions, while I am only able to add lambda, and I cannot figure out how something more general would look. – Andrea Jan 08 '11 at 11:08
  • If you care to actually read the question, I say how to create a prototype hierarchy, it is easy, using __getattr__ and __setattr__. This is not the problem, and there is no need to use metaclasses (although that would be one way to implement it). The reason why I do not make explicit examples is that I don't know what the possible syntax would be. – Andrea Jan 09 '11 at 15:14
  • About using functions defined externally and then attaching them: of course one can do this, but then the style does not really look like one is working with a prototypal language. Things get messy really soon with the namespace this way. I'm looking for something more similar to the way one declares object literals in Javascript. It is entirely conceivable that this is simply not possible in Python. – Andrea Jan 09 '11 at 15:17
  • @Andrea: And if you care to read the answer, I point out a way to do this completely without getattr/settattr or metaclasses. It's completely possible in Python, the problem is apparently that you refuse to use the functionality Python has for this because you think it "doesn't look like" a prototypal language. What you must understand is that this is done in Javascript **because Javascript doesn't have proper OO support**. Python does, and therefore you don't need to bend over backwards to do ugly prototypes. You can do it properly instead. – Lennart Regebro Jan 09 '11 at 19:52
  • @Lennart Sorry if I was rude. Still I do not see anywhere in your answer where you mention how to create a prototype hierarchy without metaclasses and without getattr. Claiming that Javascript has no proper OO support is only going to start a flame war, so I stop it now. As for using Python features: I do, I like Python and I do not want to bend its nature. The question came after some idle speculation about the possibility to mimic some language features inside another. :-) – Andrea Jan 09 '11 at 22:06
  • @Andrea: Define "prototype hierarchy". Javascript doesn't have classes. That's why you use prototypes instead. If you want a class hierarchy in Python, you use a class hierarchy. That hierarchy can be completely prototypal. The language "feature" of JS you are now trying to mimic, is in fact JS trying to mimic a feature of Python. So you are trying to mimic a feature of Python, in Python, without using the feature. This is possible, but pointless. – Lennart Regebro Jan 09 '11 at 22:19
  • You can even set a class's `__bases__` if you want. You may encounter an annoying bug if you have several classes inheriting from object, but you can also do `class object(object): pass` to get around that. – Lennart Regebro Jan 09 '11 at 22:28
  • 1
    Dear Lennart, Javascript is not trying to mimic anything. If the developers of Javascript wanted to put classes into the language, they would have added them in the first place, without the need to mimic anything. In any case the prototypal model is not only lf Javascript: you can find it in IO, Self, Lua and many other languages. – Andrea Jan 10 '11 at 10:52
  • As for the protoype hierarchy, it is very simple. If a property is not found in an object, it should be searched in the object prototype. This is simple to achieve, for instance just by storing the prototype as a property and using getattr and setattr. – Andrea Jan 10 '11 at 10:54
  • @Andrea: The OO techniques in JS use prototypes because there are no classes. Hence, it's mimicing an OO language, even though the language itself has no OO support. I don't know the other languages. Yes it is simple to achive a prototype hierarchy. **and in python you do it by making classes**. See THC4k's answer: "Python's classes are pretty equivalent to prototypes already, since you can freely change them or subclass them at runtime." You still have not added any code examples that isn't trivial to implement in Python, without gettattr/settatr or metaclasses. – Lennart Regebro Jan 10 '11 at 11:47
  • @Lennart. Let's agree to stop here. I did not add any code examples, because creating the prototype hierarchy is the easy part. I have described in words how to do it, so I do not see problems. In order to add more examples after the ones I give, I would need to be able to inline Python functions, which, it seems, is not possible. Finally, Javascript does not mimick anything. It was deliberately designed without classes: it would be stupid to design a language without classes just to mimick them later, don't you think? Javascript has prototypes instead of classes, a different way to express OO – Andrea Jan 10 '11 at 12:46
  • I agree the hierarchy is the easy part, and I told you how to do it. And **you** introduced the word "mimic". JS does not have classes, and you instead use prototypes, yes to "mimic" classes. Python **has** classes, and they are so dynamic that they can be used as prototypes. Yet you refuse to do so, for no reason whatsoever, because for some reason you want to mimic JS lack of classes in a language that has classes. If you instead, as I have tried to tel you multiple times, give some real examples, we could tell you how to do it in Python. But you refuse. Well, that's your problem. – Lennart Regebro Jan 10 '11 at 13:24
  • @Andrea: Apprently you have some religious sentiment for JS and refuse to even admit that it's OO support is extremely limited, and you apparently think that Jsvascripts way of doing things are better than Python. But if you bothered to listen, and then learn Python properly you'd notice that this isn't the case. Anything you can do in JS you can do in Python, and in most cases its' going to be easier. This is one of those cases. Except, of course, if you refuse to actually use Pythons features. Which is what you do. – Lennart Regebro Jan 10 '11 at 13:28
  • @Lennart: I really do not have any religious sentiment about any programming language whatsoever. I like both Javascript and Python, and I enjoy programming in both. I have learned Python properly, and I know how to use its features. I have asked a question about implementing a different style of programming, that's all. Peace ;-) – Andrea Jan 10 '11 at 20:40
  • Good, then you have your answer: Use classes. :-) – Lennart Regebro Jan 10 '11 at 20:57
  • -1 For not addressing prototypal programming. Mutable objects is not even half of the issue, so this shouldn't be the top answer. – Sean McMillan Jun 22 '11 at 03:14
4

Each time you read some property of Python object, method __getattribute__ is called, so you can overload it and completely control access to object's attributes. Nevertheless, for your task a bit different function - __getattr__ - may be used. In contrast to __getattribute__ it is called only if normal lookup for an attribute failed, i.e. at the same time, as prototype lookup in JavaScript starts. Here's usage:

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

Also pay attention to this question, since it has some notes on old and new style objects.

Community
  • 1
  • 1
ffriend
  • 27,562
  • 13
  • 91
  • 132
  • Nice but why do you need the `if` statement? Why not just make the whole body `return getattr(prototype, name)`? Are you worried about the `AttributeError` message in that case? – Ray Toal Jul 16 '15 at 23:06
3

This implementation contains one important enhancement over otherwise similar implementations in other answers and on the internet: the correct inheritance of methods from the prototype. If a value obtained from the prototype is a a bound instance method -- and to cover weird corner cases the method is also actually bound to that prototype -- then the method's underlying function is extracted and a new method binding that function to the calling object is returned

import types
import inspect

class Proto(object):
  def __new__(self, proto, *args, **kw):
    return super(Proto, self).__new__(self, *args, **kw)
  def __init__(self, proto, *args, **kw):
    self.proto = proto
    super(Proto, self).__init__(*args, **kw)
  def __getattr__(self, name):
    try:
      attr = getattr(self.proto, name)
      # key trick: rebind methods from the prototype to the current object
      if (inspect.ismethod(attr) and attr.__self__ is self.proto):
        attr = types.MethodType(attr.__func__, self)
      return attr
    except AttributeError:
      return super(Proto, self).__getattr__(name)

This should fully implement prototypal inheritance as I understand it. One restriction is that classes inheriting from Proto must have Proto first in their MRO because __new__ and __init__ have the prototype as the first parameter, which they drop when they delegate to super. Here is a use example:

from prototypal import Proto

class A(Proto):
  x = "This is X"
  def getY(self):
    return self._y

class B(Proto):
  _y = "This is Y"

class C(object):
  def __getattr__(self, name):
    return "So you want "+name

class D(B,C):
  pass

a = A(None) # a has no proto
b = B(a) # a is the proto for b
print b.x
print b.getY() # this will not work in most implementations

d = D(a) # a is the proto for d
print d.x
print d.getY()
print d.z

Here is the gist

Daniel Mahler
  • 7,653
  • 5
  • 51
  • 90
2

I know this is quite old, but I though I'd add my $.02:

https://gist.github.com/4142456

The only problematic thing here is adding methods. JavaScript has a far more elegant syntax with its function literals, and it's truly hard to beat that. Lambda's don't quite cut it. So my solution was to add an awkward method method for adding methods.

Doctests are included in the gist, and it all works.

EDIT:

Updated gist to no longer use method instance method. However, we still need to define the function beforehand.

At any rate, the most important part of prototypal object model is implemented in that gist. Other things are simply syntactic sugar (would be nice to have them, but it doesn't mean prototypal object model cannot be used).

  • Nice answer, only problem with direct access to `dict` or `attrs` leads to collisions. Hence in JavaScript you would have a static method like `Object.dict(my_object)` and `Object.attrs(my_object)` (to use terminology from gist). – kungfooman Sep 11 '21 at 09:02
2

Short version, yes but it's a bit more complicated than JS.

From Metaclass programming in 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')

Also check What is a metaclass in Python.

Edit : Check Prototype based OO, which is the closest thing you will get, but it will always come down to either using a lambda or just defining the function outside and adding a pointer to it to the class object.

Community
  • 1
  • 1
OneOfOne
  • 95,033
  • 20
  • 184
  • 185
  • Care to give an implementation? – aaronasterling Jan 07 '11 at 19:34
  • 1
    Yes, but the problem arises when you want to define a method that does not fit in a lambda... – Andrea Jan 07 '11 at 19:38
  • That is the implmentation, you go `X = ChattyType('X',(),{'foo':lambda self:'foo'})`. @Andrea yeah that's why I said it's a lot more complicated, you would have to define the function then add to the class. – OneOfOne Jan 07 '11 at 19:45