[Tutor] Class definitions

ThreeBlindQuarks threesomequarks at proton.me
Tue Jan 2 00:31:17 EST 2024


Dave and Alan and others,

I think this discussion is relevant but widespread in many programming languages and environments. Often there is a formal way to completely spell-out exactly what you want to do but then someone feels it involves too much typing or attention to detail and comes up with a second or third way to do it that may be simpler in common cases.

I am reminded of an annoyance in another language called R. The core language has been extended by many packages and quite a few packages decided to implement some version of piping by creating new operators. The details are not important and I will just use the word %PIPE% here to denote the many methods in pseudocode. The main point will be whether empty parentheses are allowed.

So imagine a need to open up some data (in a data.frame format) and hand it to a function that selects only certain rows and pass the result to another that filters rows that satisfy a condition and perhaps call some functions that only need a single argument like say print().

The way some of these pipes worked was to sort of interpolate what was coming down the pipe into the first argument of the next function. So if only one argument was needed, the function needed no specified parameters and thus parentheses would be empty. Since the language has functional aspects, an object that is considered a function can be passed along without parentheses, normally.

So you could say:

data %PIPE% select(...) %PIPE% filter(...) %PIPE% print()

or leave out parentheses for any function that does not need an argument or has a default as in:

data %PIPE% select(...) %PIPE% filter(...) %PIPE% head %PIPE% print

After years, some parts of the R community found these pipes so useful that the powers that be decided to add a native pipe, using a new symbol, to the language.

So instead of:

temp1 <- select(data, ...)
temp2 <- filter(temp1, ...)
temp3 <- head(temp2)
print(temp3)

You can just do::

data |> select(...) |> filter(...) |> head() |> print()

But the kicker is this nice fast implementation was not made fully compatible with the most popular variant many had been using. They required a set of empty parentheses or the code will generate errors. They also made it much more complex to pass the piped result to anything other than as a first argument.

But the tendency in many programming environments tends to be to keep adding features and python is no exception. One common feature for some kind of convenience is to allow less typing or less chance of errors. So another example might be how older languages often insisted on an exact number of arguments to many functions in exactly the same order. Sometimes you could leave some "blank" but had to leave the commas in places as in func(arg1,,arg3,,,,) and that could easily generate odd errors. Python allows quite a bit of flexibility in this regard and has a combination of positional parameters and named parameters and you can often just include options you want, perhaps named, so it is less ambiguous.

The problem is that users disagree on what is really a better choice for them. Creating a class in which you have nothing more to say on the first line, is equivalent to providing no arguments and accepting the defaults, if applicable. Much of the actual initialization in those cases is done a bit differently than with a function declaration. 

But you can argue that it is far easier to parse and evaluate code if it contains patterns that can be counted on. A name followed immediately by something (or nothing) in parentheses is easier to look for than evaluating the object more deeply to see what it is or should be. But that only applies if your language has a well-thought-out rationale and frankly, languages like Python can be quite horrible in this regard as the number of uses in distinct ways of paired parentheses is astounding. Sometimes, as with curried code, you encounter rather monstrous constructions with dangling pairs of parentheses to indicate you are calling a function that returns a function that returns a function and providing arguments to various levels.

I end by noting a reality. No matter what your personal style and choices, if you want others to read your code, or are working in a team that has made some rules/expectations, consider doing it the hard way rather than what makes it easier for you.






Sent with Proton Mail secure email.

On Monday, January 1st, 2024 at 8:08 PM, dn via Tutor <tutor at python.org> wrote:


> On 2/01/24 12:53, Alan Gauld via Tutor wrote:
> 
> > On 01/01/2024 22:05, dn via Tutor wrote:
> > 
> > > Are you training folk, or requiring in Code Reviews, the use of
> > > parentheses in stand-alone class definitions (or not)?
> > 
> > I'm not quite sure who you are addressing here?
> 
> 
> When helping folk start-out, the preference is to go with the one and
> only one way to do things.
> 
> Code Review is about (organisational) convention.
> 
> > > Accordingly, wondered if you feel there is virtue in writing class-names
> > > without parentheses, and only moving to such syntax upon reaching more
> > > advanced levels involving inheritance (and multiple-inheritance)?
> > 
> > My personal take is that it would have been consistent with
> > Python's "explicit is better" approach if class definitions
> > always required the parens with object where appropriate
> > 
> > class MyClass(object):
> > 
> > Even though it meant more typing.
> 
> 
> A useful concept to understand - but often rather too theoretical for
> first-timers.
> 
> Which has been true only since 'new style types' were brought-in
> (somewhere back in the mists of Python 2.n history). Thus, one of
> several changes to the way we define custom-classes.
> 
> > But Guido obviously thought different and we are stuck with
> > the definition structures. Since the idiomatic way of writing
> > it is to omit the parens that's what I do and encourage others
> > to do too. Idioms are powerful tools.
> 
> 
> That's what I was wondering. Is there some authoritative statement for this?
> 
> OTOH it seems a little odd, that some classes are defined with
> parentheses and others not.
> 
> Hence the 'full' parentheses indicate a sub-class, whereas the 'empty'
> ones indicate a super-class or something that stands-alone and outside
> of any hierarchy.
> 
> Consulting PEP-008 (latest update, last month) there is considerable
> discussion about "Designing for Inheritance" (much of which curls the
> hair of SOLID OOP-ers) but no mention of parentheses (that I noticed).
> Although, the one code-example does feature the ubiquitous Cartesian
> Co-ordinate as "class Point:"!?
> 
> --
> Regards,
> =dn
> _______________________________________________
> Tutor maillist - Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor


More information about the Tutor mailing list