Mailing List Archive

Changing calling sequence
I have a function that I use to retrieve daily data from a
home-brew database. Its calling sequence is;

def TempsOneDay( year, month, date ):

After using it (and its friends) for a few years, I've come to
realize that there are times where it would be advantageous to
invoke it with a datetime.date as its single argument.

As far as I can tell, there are three ways for me to proceed:
1. Write a similar function that takes a single datetime.date
as its argument.
2. Rewrite the existing function so that it takes a single
argument, which can be either a tuple of (year,month,date)
or a datetime.date argument.
3. Rewrite the existing function so that its first argument
can be either an int (for year) or a datetime.date. The
existing month and date arguments would be optional, with
default=None. But, if the first argument is an int, and
either of month or date is None, an error would be raised.

The first would be the simplest. However, it is obviously WET
rather than DRY.

The second isn't too bad, but a change like this would require that
I find all places that the function is currently used and insert a
pair of parentheses. Touching this much code is risky, as well
as being a bunch of work. (Admittedly, I'd only do it once.)

The third is really klunky, but wouldn't need to touch anything
besides this function.

What are others' thoughts? Which of the approaches above looks
least undesirable (and why)? Can anybody see a fourth approach?

--
Michael F. Stemper
This post contains greater than 95% post-consumer bytes by weight.
--
https://mail.python.org/mailman/listinfo/python-list
Re: Changing calling sequence [ In reply to ]
On 5/11/22 06:33, Michael F. Stemper wrote:
> I have a function that I use to retrieve daily data from a
> home-brew database. Its calling sequence is;
>
> def TempsOneDay( year, month, date ):
>
> After using it (and its friends) for a few years, I've come to
> realize that there are times where it would be advantageous to
> invoke it with a datetime.date as its single argument.

You could just use all keyword args:

def TempsOneDay(**kwargs):

if 'date' in kwargs:
handle_datetime(kwargs['date'])
elif 'year' in kwargs and 'month' in kwargs and 'day' in kwargs:
handle_args(kwargs['year'], kwargs['month'], kwargs['day'])
else:
raise Exception("Bad keyword args")

TempsOneDay(date=datetime.datetime.now)

TempsOneDay(year=2022, month=11, day=30)

--
https://mail.python.org/mailman/listinfo/python-list
Re: Changing calling sequence [ In reply to ]
On 2022-05-11 at 08:33:27 -0500,
"Michael F. Stemper" <michael.stemper@gmail.com> wrote:

> I have a function that I use to retrieve daily data from a
> home-brew database. Its calling sequence is;
>
> def TempsOneDay( year, month, date ):
>
> After using it (and its friends) for a few years, I've come to
> realize that there are times where it would be advantageous to
> invoke it with a datetime.date as its single argument.
>
> As far as I can tell, there are three ways for me to proceed:
> 1. Write a similar function that takes a single datetime.date
> as its argument.
> 2. Rewrite the existing function so that it takes a single
> argument, which can be either a tuple of (year,month,date)
> or a datetime.date argument.
> 3. Rewrite the existing function so that its first argument
> can be either an int (for year) or a datetime.date. The
> existing month and date arguments would be optional, with
> default=None. But, if the first argument is an int, and
> either of month or date is None, an error would be raised.
>
> The first would be the simplest. However, it is obviously WET
> rather than DRY.

It's also the least disruptive to existing code and tests, and the most
clear to readers (whether or not they're familiar with said existing
code).

What pieces, exactly, do you think you would repeat, especially after
you extract the common logic into a new function that should be simpler
than either API-level function.
--
https://mail.python.org/mailman/listinfo/python-list
RE: Changing calling sequence [ In reply to ]
>> I have a function that I use to retrieve daily data from a
>> home-brew database. Its calling sequence is;
>>
>> def TempsOneDay( year, month, date ):
>>
>> After using it (and its friends) for a few years, I've come to
>> realize that there are times where it would be advantageous to
>> invoke it with a datetime.date as its single argument.
>
>You could just use all keyword args:
>
>def TempsOneDay(**kwargs):
>
> if 'date' in kwargs:
> handle_datetime(kwargs['date'])
> elif 'year' in kwargs and 'month' in kwargs and 'day' in kwargs:
> handle_args(kwargs['year'], kwargs['month'], kwargs['day'])
> else:
> raise Exception("Bad keyword args")
>
>TempsOneDay(date=datetime.datetime.now)
>
>TempsOneDay(year=2022, month=11, day=30)
>

Maybe not the prettiest, but you could also define it like this, which also wouldn't require changing of any existing calls or the main body of the function past this if block.

def TempsOneDay(*dateComponents):
if len(dateComponents) == 3:
year, month, date = dateComponents
elif len(dateComponents) == 1 and isinstance(dateComponents[0], datetime.date):
year, month, date = (dateComponents[0].year, dateComponents[0].month, dateComponents[0].day)
else:
raise Exception("Error message here")
--
https://mail.python.org/mailman/listinfo/python-list
Re: Changing calling sequence [ In reply to ]
On 2022-05-11, David Raymond <David.Raymond@tomtom.com> wrote:

> Maybe not the prettiest, but you could also define it like this,
> which also wouldn't require changing of any existing calls or the
> main body of the function past this if block.
>
> def TempsOneDay(*dateComponents):
> if len(dateComponents) == 3:
> year, month, date = dateComponents
> elif len(dateComponents) == 1 and isinstance(dateComponents[0], datetime.date):
> year, month, date = (dateComponents[0].year, dateComponents[0].month, dateComponents[0].day)
> else:
> raise Exception("Error message here")

That would be my preference were I reading the code. It makes it quite
clear that there are two completely separate signatures. I think I
would be a little confused by the 2nd and 3rd values with default
values — the implication would be that I can supply a datetime object
as the first argument and then additional month and date values in the
2nd and 3rd args. You could try to explain it with a comment, but I
tend to ignore comments...
--
https://mail.python.org/mailman/listinfo/python-list
Re: Changing calling sequence [ In reply to ]
Why not do :

def TempsOneDayDT(date:datetime.date):
return TempsOneDay(date.year, date.month, date.day)

No repeat of code - just a different interface to the same
functionality.



------ Original Message ------
From: "Michael F. Stemper" <michael.stemper@gmail.com>
To: python-list@python.org
Sent: Wednesday, 11 May, 22 At 14:33
Subject: Changing calling sequence
I have a function that I use to retrieve daily data from a
home-brew database. Its calling sequence is;
def TempsOneDay( year, month, date ):
After using it (and its friends) for a few years, I've come to
realize that there are times where it would be advantageous to
invoke it with a datetime.date as its single argument.
As far as I can tell, there are three ways for me to proceed:
1. Write a similar function that takes a single datetime.date
as its argument.
2. Rewrite the existing function so that it takes a single
argument, which can be either a tuple of (year,month,date)
or a datetime.date argument.
3. Rewrite the existing function so that its first argument
can be either an int (for year) or a datetime.date. The
existing month and date arguments would be optional, with
default=None. But, if the first argument is an int, and
either of month or date is None, an error would be raised.

The first would be the simplest. However, it is obviously WET
rather than DRY.
The second isn't too bad, but a change like this would require that
I find all places that the function is currently used and insert a
pair of parentheses. Touching this much code is risky, as well
as being a bunch of work. (Admittedly, I'd only do it once.)
The third is really klunky, but wouldn't need to touch anything
besides this function.
What are others' thoughts? Which of the approaches above looks
least undesirable (and why)? Can anybody see a fourth approach?
--
Michael F. Stemper
This post contains greater than 95% post-consumer bytes by weight.
--
https://mail.python.org/mailman/listinfo/python-list
<https://mail.python.org/mailman/listinfo/python-list>

-- <br>Anthony Flury<br>anthony.flury@btinternet.com
--
https://mail.python.org/mailman/listinfo/python-list
RE: Changing calling sequence [ In reply to ]
>>def TempsOneDay(*dateComponents):
>> if len(dateComponents) == 3:
>> year, month, date = dateComponents
>> elif len(dateComponents) == 1 and isinstance(dateComponents[0], datetime.date):
>> year, month, date = (dateComponents[0].year, dateComponents[0].month, dateComponents[0].day)
>> else:
>> raise Exception("Error message here")
>
>|>>> help( TempsOneDay )
>|Help on function TempsOneDay in module __main__:
>|
>|TempsOneDay(*dateComponents)


Then just add an appropriate docstring.

>>> def TempsOneDay(*dateComponents):
... """Can be called either with 3 arguments: year, month, day
... or with a single datetime.date object"""
... if len(dateComponents) == 3:
... year, month, date = dateComponents
... elif len(dateComponents) == 1 and isinstance(dateComponents[0], datetime.date):
... year, month, date = (dateComponents[0].year, dateComponents[0].month, dateComponents[0].day)
... else:
... raise Exception("Error message here")
...
>>> help(TempsOneDay)
Help on function TempsOneDay in module __main__:

TempsOneDay(*dateComponents)
Can be called either with 3 arguments: year, month, day
or with a single datetime.date object

>>>
--
https://mail.python.org/mailman/listinfo/python-list
Re: Changing calling sequence [ In reply to ]
On 11/05/2022 14.58, anthony.flury wrote:

> Why not do :
>
>       def TempsOneDayDT(date:datetime.date):
>              return TempsOneDay(date.year, date.month, date.day)
>
> No repeat of code - just a different interface to the same functionality.

Yeah, a one-line wrapper around the original function seems a
lot simpler that any of my ideas. I think that I'll even use the
name from your example.

Thanks to all who posted, as well as the many lurkers who support me
in email.


--
Michael F. Stemper
Economists have correctly predicted seven of the last three recessions.
--
https://mail.python.org/mailman/listinfo/python-list
Re: Changing calling sequence [ In reply to ]
You probably want something like overload/multiple dispatch. I quick search
on PyPI yields a 'multipledispatch' package.

I never used, however.

On Wed, May 11, 2022 at 08:36:26AM -0700, Tobiah wrote:
>On 5/11/22 06:33, Michael F. Stemper wrote:
>>I have a function that I use to retrieve daily data from a
>>home-brew database. Its calling sequence is;
>>
>>def TempsOneDay( year, month, date ):
>>
>>After using it (and its friends) for a few years, I've come to
>>realize that there are times where it would be advantageous to
>>invoke it with a datetime.date as its single argument.
>
>You could just use all keyword args:
>
>def TempsOneDay(**kwargs):
>
> if 'date' in kwargs:
> handle_datetime(kwargs['date'])
> elif 'year' in kwargs and 'month' in kwargs and 'day' in kwargs:
> handle_args(kwargs['year'], kwargs['month'], kwargs['day'])
> else:
> raise Exception("Bad keyword args")
>
>TempsOneDay(date=datetime.datetime.now)
>
>TempsOneDay(year=2022, month=11, day=30)
>
>--
>https://mail.python.org/mailman/listinfo/python-list
--
https://mail.python.org/mailman/listinfo/python-list
Re: Changing calling sequence [ In reply to ]
On 12/05/2022 01.33, Michael F. Stemper wrote:
> I have a function that I use to retrieve daily data from a
> home-brew database. Its calling sequence is;
>
> def TempsOneDay( year, month, date ):
>
> After using it (and its friends) for a few years, I've come to
> realize that there are times where it would be advantageous to
> invoke it with a datetime.date as its single argument.
>
> As far as I can tell, there are three ways for me to proceed:
> 1. Write a similar function that takes a single datetime.date
>    as its argument.
> 2. Rewrite the existing function so that it takes a single
>    argument, which can be either a tuple of (year,month,date)
>    or a datetime.date argument.
> 3. Rewrite the existing function so that its first argument
>    can be either an int (for year) or a datetime.date. The
>    existing month and date arguments would be optional, with
>    default=None. But, if the first argument is an int, and
>    either of month or date is None, an error would be raised.
>
> The first would be the simplest. However, it is obviously WET
> rather than DRY.
>
> The second isn't too bad, but a change like this would require that
> I find all places that the function is currently used and insert a
> pair of parentheses. Touching this much code is risky, as well
> as being a bunch of work. (Admittedly, I'd only do it once.)
>
> The third is really klunky, but wouldn't need to touch anything
> besides this function.
>
> What are others' thoughts? Which of the approaches above looks
> least undesirable (and why)? Can anybody see a fourth approach?


Reading the above, it seems that the options are limited to using
positional-arguments only. Because I keep tripping-over my long, grey,
beard; I'm reminded that relying upon my/human memory is, um, unreliable
(at least in my case). Accordingly, by the time a function's definition
reaches three parameters, I'll be converting it to use keyword-arguments
as a matter of policy. YMMV!

Remember: if keyword arguments are not used (ie existing/legacy code),
Python will still use positional logic.

Once the function's signature has been changed, we could then add
another keyword-parameter to cover the datetime option.


That said, a function which starts with a list of ifs-buts-and-maybes*
which are only there to ascertain which set of arguments have been
provided by the calling-routine; obscures the purpose/responsibility of
the function and decreases its readability (perhaps not by much, but
varying by situation).

Accordingly, if the function is actually a method, recommend following
@Stefan's approach, ie multiple-constructors. Although, this too can
result in lower readability.

Assuming it is a function, and that there are not many alternate
APIs/approaches (here we're discussing only two), I'd probably create a
wrapper-function which has the sole task of re-stating the datetime
whilst calling the existing three-parameter function. The readability
consideration here, is to make a good choice of (new) function-name!


* Python version >= 10? Consider using match-case construct keyed on
parameter-type
--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: Changing calling sequence [ In reply to ]
On 2022-05-15 at 10:22:15 +1200,
dn <PythonList@DancesWithMice.info> wrote:

> That said, a function which starts with a list of ifs-buts-and-maybes*
> which are only there to ascertain which set of arguments have been
> provided by the calling-routine; obscures the purpose/responsibility
> of the function and decreases its readability (perhaps not by much,
> but varying by situation).

Agreed.

> Accordingly, if the function is actually a method, recommend following
> @Stefan's approach, ie multiple-constructors. Although, this too can
> result in lower readability.

(Having proposed that approach myself (and having used it over the
decades for functions, methods, procedures, constructors, ...), I also
agree.)

Assuming good names,? how can this lead to lower readability? I guess
if there's too many of them, or programmers have to start wondering
which one to use? Or is this in the same generally obfuscating category
as the ifs-buts-and-maybes at the start of a function?

? and properly invalidated caches
--
https://mail.python.org/mailman/listinfo/python-list
Re: Changing calling sequence [ In reply to ]
On 15/05/2022 11.34, 2QdxY4RzWzUUiLuE@potatochowder.com wrote:
> On 2022-05-15 at 10:22:15 +1200,
> dn <PythonList@DancesWithMice.info> wrote:
>
>> That said, a function which starts with a list of ifs-buts-and-maybes*
>> which are only there to ascertain which set of arguments have been
>> provided by the calling-routine; obscures the purpose/responsibility
>> of the function and decreases its readability (perhaps not by much,
>> but varying by situation).
>
> Agreed.
>
>> Accordingly, if the function is actually a method, recommend following
>> @Stefan's approach, ie multiple-constructors. Although, this too can
>> result in lower readability.
>
> (Having proposed that approach myself (and having used it over the
> decades for functions, methods, procedures, constructors, ...), I also
> agree.)
>
> Assuming good names,¹ how can this lead to lower readability? I guess
> if there's too many of them, or programmers have to start wondering
> which one to use? Or is this in the same generally obfuscating category
> as the ifs-buts-and-maybes at the start of a function?
>
> ¹ and properly invalidated caches

Allow me to extend the term "readability" to include "comprehension".
Then add the statistical expectation that a class has only __init__().
Thus, assuming this is the first time (or, ... for a while) that the
class is being employed, one has to read much further to realise that
there are choices of constructor.


Borrowing from the earlier example:

> This would be quite pythonic. For example, "datetime.date"
> has .fromtimestamp(timestamp), .fromordinal(ordinal),
> .fromisoformat(date_string), ...

Please remember that this is only relevant if the function is actually a
module - which sense does not appear from the OP (IMHO).

The alternatives' names are well differentiated and (apparently#)
appropriately named*.


* PEP-008 hobgoblins will quote:
"Function names should be lowercase, with words separated by underscores
as necessary to improve readability.
Variable names follow the same convention as function names."
- but this is a common observation/criticism of code that has been in
the PSL for a long time.

# could also criticise as not following the Software Craftsmanship/Clean
Code ideal of 'programming to the interface rather than the
implementation' - which we see in PEP-008 as "usage rather than
implementation"
(but please don't ask me how to differentiate between them, given that
the only reason for the different interfaces is the
function's/parameters' implementation!)

NB usual caveats apply to PEP-008 quotations!


So, I agree with you - it comes down to those pernicious
'ifs-buts-and-maybes'. If the interface/parameter-processing starts to
obfuscate the function's actual purpose, maybe it can be 'farmed-out' to
a helper-function. However, that would start to look very much like the
same effort (and comprehension-challenge) as having a wrapper-function!


Continuing the 'have to read further' criticism (above), it could
equally-well be applied to my preference for keyword-arguments, in that
I've suggested defining four parameters but the user will only call the
function with either three or one argument(s). Could this be described
as potentially-confusing?


Given that the OP wouldn't want to have to redefine the existing
interface, the next comment may not be applicable - but in the interests
of completeness: anyone contemplating such architecture might like to
consider "Single-dispatch generic functions"
(https://peps.python.org/pep-0443/). At least the decorators signal that
there are alternative-choices...
--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: Changing calling sequence [ In reply to ]
On Sun, 15 May 2022 at 14:27, dn <PythonList@danceswithmice.info> wrote:
>
> On 15/05/2022 11.34, 2QdxY4RzWzUUiLuE@potatochowder.com wrote:
> > On 2022-05-15 at 10:22:15 +1200,
> > dn <PythonList@DancesWithMice.info> wrote:
> >
> >> That said, a function which starts with a list of ifs-buts-and-maybes*
> >> which are only there to ascertain which set of arguments have been
> >> provided by the calling-routine; obscures the purpose/responsibility
> >> of the function and decreases its readability (perhaps not by much,
> >> but varying by situation).
> >
> > Agreed.
> >
> >> Accordingly, if the function is actually a method, recommend following
> >> @Stefan's approach, ie multiple-constructors. Although, this too can
> >> result in lower readability.
> >
> > (Having proposed that approach myself (and having used it over the
> > decades for functions, methods, procedures, constructors, ...), I also
> > agree.)
> >
> > Assuming good names,¹ how can this lead to lower readability? I guess
> > if there's too many of them, or programmers have to start wondering
> > which one to use? Or is this in the same generally obfuscating category
> > as the ifs-buts-and-maybes at the start of a function?
> >
> > ¹ and properly invalidated caches
>
> Allow me to extend the term "readability" to include "comprehension".
> Then add the statistical expectation that a class has only __init__().

(Confusing wording here: a class usually has far more than just
__init__, but I presume you mean that the signature of __init__ is the
only way to construct an object of that type.)

> Thus, assuming this is the first time (or, ... for a while) that the
> class is being employed, one has to read much further to realise that
> there are choices of constructor.

Yeah. I would generally say, though, that any classmethod should be
looked at as a potential alternate constructor, or at least an
alternate way to obtain objects (eg preconstructed objects with
commonly-used configuration - imagine a SecuritySettings class with a
classmethod to get different defaults).

> Borrowing from the earlier example:
>
> > This would be quite pythonic. For example, "datetime.date"
> > has .fromtimestamp(timestamp), .fromordinal(ordinal),
> > .fromisoformat(date_string), ...
>
> Please remember that this is only relevant if the function is actually a
> module - which sense does not appear from the OP (IMHO).
>
> The alternatives' names are well differentiated and (apparently#)
> appropriately named*.
>
>
> * PEP-008 hobgoblins will quote:
> "Function names should be lowercase, with words separated by underscores
> as necessary to improve readability.

Note the "as necessary". Underscores aren't required when readability
is fine without them (see for instance PEP 616, which recently added
two methods to strings "removeprefix" and "removesuffix", no
underscores - part of the argument here was consistency with other
string methods, but it's also not a major problem for readability
here).

> Variable names follow the same convention as function names."
> - but this is a common observation/criticism of code that has been in
> the PSL for a long time.
>
> # could also criticise as not following the Software Craftsmanship/Clean
> Code ideal of 'programming to the interface rather than the
> implementation' - which we see in PEP-008 as "usage rather than
> implementation"
> (but please don't ask me how to differentiate between them, given that
> the only reason for the different interfaces is the
> function's/parameters' implementation!)
>
> NB usual caveats apply to PEP-008 quotations!

Notably here, the caveat that PEP 8 is not a permanent and unchanging
document. It is advice, not rules, and not all code in the standard
library fully complies with its current recommendations.

> Continuing the 'have to read further' criticism (above), it could
> equally-well be applied to my preference for keyword-arguments, in that
> I've suggested defining four parameters but the user will only call the
> function with either three or one argument(s). Could this be described
> as potentially-confusing?

Yes, definitely. Personally, I'd split it into two, one that takes the
existing three arguments (preferably with the same name, for
compatibility), and one with a different name that takes just the one
arg. That could be a small wrapper that calls the original, or the
original could become a wrapper that calls the new one, or the main
body could be refactored into a helper that they both call. It all
depends what makes the most sense internally, because that's not part
of the API at that point.

But it does depend on how the callers operate. Sometimes it's easier
to have a single function with switchable argument forms, other times
it's cleaner to separate them.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: Changing calling sequence [ In reply to ]
On 2022-05-15 at 14:44:09 +1000,
Chris Angelico <rosuav@gmail.com> wrote:

> On Sun, 15 May 2022 at 14:27, dn <PythonList@danceswithmice.info> wrote:
> >
> > On 15/05/2022 11.34, 2QdxY4RzWzUUiLuE@potatochowder.com wrote:
> > > On 2022-05-15 at 10:22:15 +1200,
> > > dn <PythonList@DancesWithMice.info> wrote:
> > >
> > >> That said, a function which starts with a list of ifs-buts-and-maybes*
> > >> which are only there to ascertain which set of arguments have been
> > >> provided by the calling-routine; obscures the purpose/responsibility
> > >> of the function and decreases its readability (perhaps not by much,
> > >> but varying by situation).
> > >
> > > Agreed.
> > >
> > >> Accordingly, if the function is actually a method, recommend following
> > >> @Stefan's approach, ie multiple-constructors. Although, this too can
> > >> result in lower readability.
> > >
> > > (Having proposed that approach myself (and having used it over the
> > > decades for functions, methods, procedures, constructors, ...), I also
> > > agree.)
> > >
> > > Assuming good names,? how can this lead to lower readability? I guess
> > > if there's too many of them, or programmers have to start wondering
> > > which one to use? Or is this in the same generally obfuscating category
> > > as the ifs-buts-and-maybes at the start of a function?
> > >
> > > ? and properly invalidated caches
> >
> > Allow me to extend the term "readability" to include "comprehension".
> > Then add the statistical expectation that a class has only __init__().

Aha. In that light, yeah, in geeral, the more stuff there is, the
harder it is to get your head around it. And even if I document the
class (or the module), no one makes the time to read (let alone
comprehend) the document, which *should* clarify all those things that
are hard to discern from the code itself.

> > Thus, assuming this is the first time (or, ... for a while) that the
> > class is being employed, one has to read much further to realise that
> > there are choices of constructor.
>
> Yeah. I would generally say, though, that any classmethod should be
> looked at as a potential alternate constructor, or at least an
> alternate way to obtain objects (eg preconstructed objects with
> commonly-used configuration - imagine a SecuritySettings class with a
> classmethod to get different defaults).

I think opening up the class and sifting through its classmethods to
find the factory functions is what dn is talking about. Such a design
also means that once I have a SecuritySettings object, its (the
instance's) methods include both instance and class level methods. IMO,
classmethods were/are a bad idea (yes, I'm probably in the minority
around here, but someone has to be). The first person to scream "but
discoverability" will be severely beaten with a soft cushion.

> > Borrowing from the earlier example:
> >
> > > This would be quite pythonic. For example, "datetime.date"
> > > has .fromtimestamp(timestamp), .fromordinal(ordinal),
> > > .fromisoformat(date_string), ...
> >
> > Please remember that this is only relevant if the function is actually a
> > module - which sense does not appear from the OP (IMHO).

Note that datetime.date is a class, not a module.

> > The alternatives' names are well differentiated and (apparently#)
> > appropriately named*.

[...]

> > Continuing the 'have to read further' criticism (above), it could
> > equally-well be applied to my preference for keyword-arguments, in that
> > I've suggested defining four parameters but the user will only call the
> > function with either three or one argument(s). Could this be described
> > as potentially-confusing?

Potentially. :-)

In a well designed *library*, common keywords across multiple functions
provide consistency, which is generally good. Even a bit of redundancy
can be good for the same reason.

OTOH, when there's only one function, and it has a pile of keyword
parameters that can only be used in certain combinations, then it
definitely can be harder to read/understand/use than separate functions
with simpler interfaces.

> Yes, definitely. Personally, I'd split it into two, one that takes the
> existing three arguments (preferably with the same name, for
> compatibility), and one with a different name that takes just the one
> arg. That could be a small wrapper that calls the original, or the
> original could become a wrapper that calls the new one, or the main
> body could be refactored into a helper that they both call. It all
> depends what makes the most sense internally, because that's not part
> of the API at that point.
>
> But it does depend on how the callers operate. Sometimes it's easier
> to have a single function with switchable argument forms, other times
> it's cleaner to separate them.

"Easier" and "cleaner" are very often orthogonal. ;-) (Rich Hickey
(creator of Clojure) talks a lot about the difference between "easy" and
"simple." Arguemnts for and against Unix often involve similar terms.)

And "easier" or "cleaner" for whom? The person writing the function(s),
the person writing code that calls the function(s), the person reading
the function(s), the person reading code that calls the function(s), all
or any of that code? Testers? Maintainers? Their code? Sometimes,
what's easier and cleaner for one is harder and dirtier for another.

As one whose beard likely resembles dn's, I can often spot code written
by developers who have never been involved in testing or maintenance, or
code written by testers who have never written production code (and
don't/won't realize or admit that some tests *are* production code).
--
https://mail.python.org/mailman/listinfo/python-list
Re: Changing calling sequence [ In reply to ]
On 16/05/22 1:20 am, 2QdxY4RzWzUUiLuE@potatochowder.com wrote:
> IMO,
> classmethods were/are a bad idea (yes, I'm probably in the minority
> around here, but someone has to be).

I don't think class methods are a bad idea per se, but having
them visible through instances seems unnecessary and confusing.
I suspect that wasn't a deliberate design decision, but just a
side effect of using a single class dict for both class and
instance things.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list