[Python-ideas] JavaScript-Style Object Creation in Python (using a constructor function instead of a class to create objects)

Stephan Houben stephanh42 at gmail.com
Sun May 14 03:45:20 EDT 2017


FWIW, Javascript itself is moving away from this syntax in favour of a more
Python-like syntax based on the 'class' keyword. This was introduced in
EcmaScript 2015.

Stephan

Op 14 mei 2017 09:35 schreef "Simon Ramstedt" <simonramstedt at gmail.com>:

> Hi, thanks a lot for your feedback!
>
> On Sun, May 14, 2017, 00:54 Brendan Barnwell <brenbarn at brenbarn.net>
> wrote:
>
>> On 2017-05-13 21:07, Simon Ramstedt wrote:
>> > Hi, do you have an opinion on the following?
>>
>>         My general opinion is that imitating JavaScript is almost always
>> a bad
>> idea.  :-)
>>
>> > Wouldn't it be nice to define classes via a simple constructor function
>> > (as below) instead of a conventional class definition?
>> >
>> > *conventional*:
>> > |
>> > classMyClass(ParentClass):
>> > def__init__(x):
>> > self._x=x
>> > defmy_method(y):
>> >          z=self._x+y
>> > returnz
>> > |
>> >
>> >
>> > *proposed*:
>> >
>> > |
>> > defMyClass(x):
>> > self=ParentClass()
>> > defmy_method(y):
>> >          z=x+y
>> > returnz
>> > self.my_method=my_method # that's cumbersome (see comments below)
>> > returnself
>> > |
>> >
>> >
>> > Here are the pros and cons I could come up with for the proposed method:
>> >
>> > (+) Simpler and more explicit.
>>
>>         I don't really see how that's simpler or more explicit.  In one
>> respect
>> it's clearly less explicit, as the "self" is implicit.
>>
>> > (+) No need to create attributes (like `self._x`) just to pass something
>> > from `__init__` to another method.
>>
>>         Attributes aren't just for passing things to other methods.
>> They're
>> for storing state.  In your proposed system, how would an object mutate
>> one of its own attributes?  It looks like "x" here is just stored in a
>> function closure, which wouldn't allow easy mutation.  Also, how would
>> another object access the attribute from outside (as we currently do
>> with self.x)?  You can say we'd only use this new attribute-free
>> approach when we want to pass a constructor argument that's used but
>> never mutated or accessed from outside, but that severely restricts the
>> potential use cases, and all it saves you is typing "self".
>>
>
> Attributes could be added to self just as in conventional classes if they
> are needed.
>
>
>>         Relatedly, how is ParentClass itself defined?  I don't see how you
>> could bootstrap this without having a real class at the bottom of it
>> somehow (as your test script in fact does).
>>
>
> You could bootstrap with an object base class/constructor just as normal
> classes inherit from object. Also the normal class system should remain in
> any case in order not to break every python library.
>
>>
>> > (+) Default arguments / annotations for methods could be different for
>> > each class instance. Adaptive defaults wouldn't have to simulated with a
>> > None.
>>
>>         That seems as likely to be a negative as a positive.  Having
>> different
>> instances with different default values could be confusing.  This would
>> even allow different instances to define totally different methods (with
>> if-logic inside the function constructor), which would definitely be
>> confusing.
>>
>
> Different default values for different instances are a corner case but
> they are already happening by setting default to None. Defining different
> methods for different instances wouldn't be good but that is also possible
> with conventional classes (by adding functions to self in __init__).
>
> > (+) Class/instance level imports would work.
>>
>>         How often is that really needed?
>>
>
> True, usually it doesn't matter. But when using big packages like
> tensorflow that take several seconds to load it can be annoying. Its always
> loaded when importing any library that uses it internally, because of
> module level imports that should be class/instance level. Even if we just
> wanted to do --help on the command line and needed that library before
> argparse for some reason.
>
> > (-/+) Speed: The `def`-based objects take 0.6 μs to create while the
>> > `class`-based objects take only 0.4 μs. For method execution however the
>> > closure takes only 0.15 μs while the proper method takes 0.22 μs (script
>> > <https://gist.github.com/rmst/78b2b0f56a3d9ec13b1ec6f3bd50aa9c>).
>>
>>         I don't think you can really evaluate the performance impact of
>> this
>> alternative just based on a trivial example like that.
>>
>> Agree, I don't know really how well this would perform.
>>
>
> > (-/+) Checking types: In the proposed example above the returned object
>> > wouldn't know that it has been created by `MyClass`. There are a couple
>> > of solutions to that, though. The easiest to implement would be to
>> > change the first line to `self = subclass(ParentClass())` where the
>> > subclass function looks at the next item in the call stack (i.e.
>> > `MyClass`) and makes it the type of the object. Another solution would
>> > be to have a special rule for functions with capital first letter
>> > returning a single object to append itself to the list of types of the
>> > returned object. Alternatively there could be a special keyword e.g.
>> > `classdef` that would be used instead of `def` if we wouldn't want to
>> > rely on the name.
>>
>>         Those special rules sound very hackish to me.
>
>
>> > (-) The current syntax for adding a function to an object is
>> > cumbersome.  That's what is preventing me from actually using the
>> > proposed pattern. But is this really the only reason for not using it?
>> > And if so, wouldn't that be a good argument for enabling something like
>> > below?
>> > *
>> > *
>> > *attribute function definitions*:
>> > |
>> > defMyClass(x):
>> > self=ParentClass()
>> > defself.my_method(y):
>> >          z=x+y
>> > returnz
>> > returnself
>> > |
>> >
>> >
>> > or alternatively*multiline lambdas*:
>> >
>> > |
>> > defMyClass(x):
>> > self=ParentClass()
>> > self.my_method=(y):
>> >          z=x+y
>> > returnz
>> > returnself
>> > |
>>
>>         To be honest, from all your examples, I don't really see what the
>> point
>> is.  It's a different syntax for doing some of the same things the
>> existing class syntax does, while providing no apparent way to do some
>> important things (like mutating attributes).  I think Python's existing
>> class syntax is simple, clear, and quite nice overall, and creating
>> class instances by calling a function instead of a class doesn't add
>> anything.  In fact, even JavaScript has recently added classes to allow
>> programmers to move away from the old approach that you describe here.
>> Also, as I alluded to above, JavaScript is so terrible in so many ways
>> that the mere idea of imitating it inherently makes me skeptical;
>> there's almost nothing about JavaScript's design that couldn't be done
>> better, and most of what it does are things that Python already does
>> better and has done better for years.  In short, I don't see any
>> advantages at all to doing classes this way, and there are some
>> non-negligible disadvantages.
>>
>
> Interesting, didn't know that about Javascript. I also don't like
> Javascript's prototypes very much but thought adding "JavaScript-like" to
> the title might help explain what I meant.
>
> Leaving the possible replacement for classes aside, do you have an opinion
> specifically about the following?
>
> def obj.my_function(a, b):
>    ...
>
> as syntactic sugar for
>
> def my_function(a, b):
>   ...
>
> obj.my_function = my_function
>
> In my experience this pattern comes actually up quite a bit. E.g. when
> working with these "symbolic" machine learning frameworks like theano or
> tensorflow. Apart from that it mixins very easy.
>
> What do you think are the odds of something like this actually making it
> into the Python and if greater than 0 in which timeframe?
>
>
>
>> --
>> Brendan Barnwell
>> "Do not follow where the path may lead.  Go, instead, where there is no
>> path, and leave a trail."
>>     --author unknown
>> _______________________________________________
>> Python-ideas mailing list
>> Python-ideas at python.org
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
>
>
> Thanks,
>
> Simon
>
>>
>>
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20170514/0a8a0640/attachment-0001.html>


More information about the Python-ideas mailing list