Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #82286 > unrolled thread

How to detect that a function argument is the default one

Started by"ast" <nomail@invalid.com>
First post2014-12-10 16:14 +0100
Last post2014-12-12 10:03 +1100
Articles 13 — 9 participants

Back to article view | Back to comp.lang.python


Contents

  How to detect that a function argument is the default one "ast" <nomail@invalid.com> - 2014-12-10 16:14 +0100
    Re: How to detect that a function argument is the default one Skip Montanaro <skip.montanaro@gmail.com> - 2014-12-10 09:29 -0600
      Re: How to detect that a function argument is the default one "ast" <nomail@invalid.com> - 2014-12-10 16:45 +0100
      Re: How to detect that a function argument is the default one Marko Rauhamaa <marko@pacujo.net> - 2014-12-10 18:33 +0200
    Re: How to detect that a function argument is the default one Chris Angelico <rosuav@gmail.com> - 2014-12-11 03:16 +1100
      Re: How to detect that a function argument is the default one wxjmfauth@gmail.com - 2014-12-10 12:08 -0800
      Re: How to detect that a function argument is the default one "ast" <nomail@invalid.com> - 2014-12-10 22:17 +0100
        Re: How to detect that a function argument is the default one Ian Kelly <ian.g.kelly@gmail.com> - 2014-12-11 11:03 -0700
        Re: How to detect that a function argument is the default one Ian Kelly <ian.g.kelly@gmail.com> - 2014-12-11 11:07 -0700
    Re: How to detect that a function argument is the default one Ned Batchelder <ned@nedbatchelder.com> - 2014-12-10 11:19 -0500
    Re: How to detect that a function argument is the default one Ian Kelly <ian.g.kelly@gmail.com> - 2014-12-10 09:20 -0700
    Re: How to detect that a function argument is the default one Tony the Tiger <tony@tiger.invalid> - 2014-12-11 19:45 +0000
      Re: How to detect that a function argument is the default one Ben Finney <ben+python@benfinney.id.au> - 2014-12-12 10:03 +1100

#82286 — How to detect that a function argument is the default one

From"ast" <nomail@invalid.com>
Date2014-12-10 16:14 +0100
SubjectHow to detect that a function argument is the default one
Message-ID<5488634e$0$2130$426a74cc@news.free.fr>
Hello


Here is what I would like to implement

class Circle:

    def __init__(center=(0,0), radius=10, mass=1)):
        self.center = center
        self.radius = radius

        if  "mass is the default one":       <-----
            self.mass = radius**2
        else:
            self.mass = mass

I cant just test if mass == 1: because if I call
C1 = Circle((0,0), 7, 1)
then in that case I want: self.mass = 1

If i call  C2 = Circle((6,8), 8) 
then in that case I want: self.mass = radius**2

I have the idea to write:

def __init__(center=(0,0), radius=10, mass=None)):

    if  mass == None: 
        self.mass = radius**2
    else:
        self.mass = mass

but maybe Python provides something clever.

Thx

[toc] | [next] | [standalone]


#82287

FromSkip Montanaro <skip.montanaro@gmail.com>
Date2014-12-10 09:29 -0600
Message-ID<mailman.16809.1418225382.18130.python-list@python.org>
In reply to#82286
On Wed, Dec 10, 2014 at 9:14 AM, ast <nomail@invalid.com> wrote:
> I have the idea to write:
>
> def __init__(center=(0,0), radius=10, mass=None)):
>
>    if  mass == None:        self.mass = radius**2
>    else:
>        self.mass = mass
>
> but maybe Python provides something clever.

This is almost the correct idiom. In general, pick defaults from
values outside your valid domain. None is often perfect for
this. Since you're comparing to a singleton value, "is" is the usual
comparison, so your code becomes:

def __init__(center=(0,0), radius=10, mass=None)):
    if mass is None:
        self.mass = radius**2
    else:
        self.mass = mass

At the programming level, Python generally tries not to be too clever,
especially for real basic stuff. From the Zen of Python:

    >>> import this
    The Zen of Python, by Tim Peters

    ...
    Explicit is better than implicit.
    ...

Guido could have been more clever here, but it wouldn't have likely
gained much (you'd still have to detect the default and set the value
appropriately), and perhaps made the code a (small) bit harder to
read.

Skip

[toc] | [prev] | [next] | [standalone]


#82288

From"ast" <nomail@invalid.com>
Date2014-12-10 16:45 +0100
Message-ID<54886aa0$0$2103$426a74cc@news.free.fr>
In reply to#82287
"Skip Montanaro" <skip.montanaro@gmail.com> a écrit dans le message de 
news:mailman.16809.1418225382.18130.python-list@python.org...
> On Wed, Dec 10, 2014 at 9:14 AM, ast <nomail@invalid.com> wrote:

thx 

[toc] | [prev] | [next] | [standalone]


#82296

FromMarko Rauhamaa <marko@pacujo.net>
Date2014-12-10 18:33 +0200
Message-ID<8761djjwgm.fsf@elektro.pacujo.net>
In reply to#82287
Skip Montanaro <skip.montanaro@gmail.com>:

> On Wed, Dec 10, 2014 at 9:14 AM, ast <nomail@invalid.com> wrote:
>> I have the idea to write:
>>
>> def __init__(center=(0,0), radius=10, mass=None)):
>>
>>    if  mass == None:        self.mass = radius**2
>>    else:
>>        self.mass = mass
>>
>> but maybe Python provides something clever.
>
> This is almost the correct idiom. In general, pick defaults from
> values outside your valid domain. None is often perfect for
> this. Since you're comparing to a singleton value, "is" is the usual
> comparison, so your code becomes:
>
> def __init__(center=(0,0), radius=10, mass=None)):
>     if mass is None:
>         self.mass = radius**2
>     else:
>         self.mass = mass

In this case, None works well. However, sometimes None is a valid input
value. Then, a sentinel object is the way out:

        
    _OMITTED = object()

    class SomeClass:
        def __init__(self, center=(0,0), radius=10, mass=_OMITTED)):
            if mass is _OMITTED:
                self.mass = radius**2
            else:
                self.mass = mass


Marko

[toc] | [prev] | [next] | [standalone]


#82293

FromChris Angelico <rosuav@gmail.com>
Date2014-12-11 03:16 +1100
Message-ID<mailman.16814.1418228205.18130.python-list@python.org>
In reply to#82286
On Thu, Dec 11, 2014 at 3:10 AM, Jean-Michel Pichavant
<jeanmichel@sequans.com> wrote:
> ----- Original Message -----
>> From: "ast" <nomail@invalid.com>
>> I have the idea to write:
>>
>> def __init__(center=(0,0), radius=10, mass=None)):
>>
>>     if  mass == None:
>>         self.mass = radius**2
>>     else:
>>         self.mass = mass
>>
>> but maybe Python provides something clever.
>>
>> Thx
>
> If you like one-liners,
>
> def __init__(self, center=(0,0), radius=10, mass=None):
>     self.center = center
>     self.radius = radius
>     self.mass = (mass is None and radius**2) or mass

Leaving aside the obvious point that not everything needs to be a
one-liner, there is a MUCH better way to spell this: the if/else
ternary expression.

self.mass = radius**2 if mass is None else mass

> But there's an issue with that solution: self.mass being computed during the instance initialization, what if radius is changing ?
>
> c1 = Circle((0,0), 10, None)
> print c1.mass
> 20
> c1.radius = 20
> print c1.mass
> 20 # that is unexpected
>
> Everytime an attribute is computed from another attribute, it should ring a python bell : property
>
> def __init__(self, center, radius, mass):
>     self.center = center
>     self.radius = radius
>     self._mass = mass
>
>     @property
>     def mass(self):
>          return self._mass if self._mass is not None else self.radius*2
>
>
> c1 = Circle((0,0), 10, None)
> print c1.mass
> 20
> c1.radius = 20
> print c1.mass
> 40

I think that juuuuuust miiiiight count as scope creep :) Though it
does highlight an interesting point, namely that sometimes the state
of "argument wasn't specified" needs to carry through into an object's
"attribute wasn't specified".

> Note : what is the mass of a circle ?

Fortunately for us, this is a programming class, not a philosophical
one. Maybe the circles in question are being cast in steel? :)

ChrisA

[toc] | [prev] | [next] | [standalone]


#82308

Fromwxjmfauth@gmail.com
Date2014-12-10 12:08 -0800
Message-ID<088efe53-3178-4f45-9be5-9d55fa96f1ff@googlegroups.com>
In reply to#82293
Le mercredi 10 décembre 2014 17:17:03 UTC+1, Chris Angelico a écrit :
> 
> Fortunately for us, this is a programming class, not a philosophical
> one. Maybe the circles in question are being cast in steel? :)
> 


I belong to those, who think thid kind of stuff is
important. (I wrote enough simulation programs in
the field of quantum chemistry to know how this
kind of clarity is very relevant).

self.mass [kg] =? radius ** 2 [m²]

Today, there are people who are confusing character and code point...

jmf

[toc] | [prev] | [next] | [standalone]


#82310

From"ast" <nomail@invalid.com>
Date2014-12-10 22:17 +0100
Message-ID<5488b874$0$2890$426a34cc@news.free.fr>
In reply to#82293
"Chris Angelico" <rosuav@gmail.com> a écrit dans le message de 
news:mailman.16814.1418228205.18130.python-list@python.org...
> On Thu, Dec 11, 2014 at 3:10 AM, Jean-Michel Pichavant
> <jeanmichel@sequans.com> wrote:
>> ----- Original Message -----
>>> From: "ast" <nomail@invalid.com>

>> But there's an issue with that solution: self.mass being computed
>> during the instance initialization, what if radius is changing ?

You are going to laught because i had that bug ... LOL

>> Everytime an attribute is computed from another attribute, it should ring a python bell : 
>> property

yes


>
>> Note : what is the mass of a circle ?
>

In fact it's a ball moving in a plan.
I will change that name. 

[toc] | [prev] | [next] | [standalone]


#82368

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-12-11 11:03 -0700
Message-ID<mailman.16860.1418321042.18130.python-list@python.org>
In reply to#82310

[Multipart message — attachments visible in raw view] — view raw

On Thu, Dec 11, 2014 at 3:02 AM, Jean-Michel Pichavant <
jeanmichel@sequans.com> wrote:
> I would advise to remove the the mass parameter of your Sphere
initialization. It could be inconsistent with the radius.
> To compute the mass you would need the radius and the  volumetric mass
density.

You assume a three-dimensional universe. Clearly this is a two-dimensional
"ball" with a density equal to pi/2 mass units per area unit.

[toc] | [prev] | [next] | [standalone]


#82369

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-12-11 11:07 -0700
Message-ID<mailman.16861.1418321314.18130.python-list@python.org>
In reply to#82310

[Multipart message — attachments visible in raw view] — view raw

On Thu, Dec 11, 2014 at 11:03 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
>
> On Thu, Dec 11, 2014 at 3:02 AM, Jean-Michel Pichavant <
jeanmichel@sequans.com> wrote:
> > I would advise to remove the the mass parameter of your Sphere
initialization. It could be inconsistent with the radius.
> > To compute the mass you would need the radius and the  volumetric mass
density.
>
> You assume a three-dimensional universe. Clearly this is a
two-dimensional "ball" with a density equal to pi/2 mass units per area
unit.

Er. 2/pi.

[toc] | [prev] | [next] | [standalone]


#82294

FromNed Batchelder <ned@nedbatchelder.com>
Date2014-12-10 11:19 -0500
Message-ID<mailman.16815.1418228392.18130.python-list@python.org>
In reply to#82286
On 12/10/14 11:10 AM, Jean-Michel Pichavant wrote:
>      self.mass = (mass is None and radius**2) or mass

When will this idiom die?  We've had actual if-expressions for a while now:

     self.mass = radius**2 if mass is None else mass

-- 
Ned Batchelder, http://nedbatchelder.com

[toc] | [prev] | [next] | [standalone]


#82295

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-12-10 09:20 -0700
Message-ID<mailman.16816.1418228498.18130.python-list@python.org>
In reply to#82286

[Multipart message — attachments visible in raw view] — view raw

On Wed, Dec 10, 2014 at 9:10 AM, Jean-Michel Pichavant <
jeanmichel@sequans.com> wrote:
> If you like one-liners,
>
> def __init__(self, center=(0,0), radius=10, mass=None):
>     self.center = center
>     self.radius = radius
>     self.mass = (mass is None and radius**2) or mass

If mass is None and radius is 0, then self.mass gets set to None. Use the
actual ternary operator instead.

[toc] | [prev] | [next] | [standalone]


#82392

FromTony the Tiger <tony@tiger.invalid>
Date2014-12-11 19:45 +0000
Message-ID<5489f45d$0$53762$c3e8da3$3304c218@news.astraweb.com>
In reply to#82286
On Wed, 10 Dec 2014 16:14:17 +0100, ast wrote:

>     def __init__(center=(0,0), radius=10, mass=1)):
>         self.center = center self.radius = radius
> 
>         if  "mass is the default one":       <-----
>             self.mass = radius**2

How about:

radius='10', mass='1'

if radius == '10' ...

if mass == '1' ...

You could do int(radius) and int(mass) right after, or float().


 /Grrr
-- 
          ___                  ___
 (\_--_/)  | _ ._    _|_|_  _   |o _  _ ._
 ( 9  9 )  |(_)| |\/  |_| |(/_  ||(_|(/_|
 stripes are forever - as overripe ferrets

[toc] | [prev] | [next] | [standalone]


#82394

FromBen Finney <ben+python@benfinney.id.au>
Date2014-12-12 10:03 +1100
Message-ID<mailman.16879.1418339026.18130.python-list@python.org>
In reply to#82392
Tony the Tiger <tony@tiger.invalid> writes:

> radius='10', mass='1'
>
> if radius == '10' ...
>
> if mass == '1' ...

This ignores the problem as stated: The OP wants to distinguish between
a value that was explicitly set by the caller, versus a value that was
set by default because the caller did not specify the parameter.

The general solution to this is to choose a value outside the domain, a
<URL:https://en.wikipedia.org/wiki/Sentinel_value> which is different
from any value the caller would choose for that parameter.

Often, the Python singleton ‘None’ is good for the purpose. I think in
this case, where the domain is numeric, a default of ‘None’ would do
fine.

    class Foo:
        def __init__(centre=(0, 0), radius=None, mass=None):
            if radius is None:
                # Caller didn't specify. Set a default value.
                radius = 10
            if mass is None:
                # Caller didn't specify. Set a default value.
                mass = 1
            self.centre = centre
            self.radius = radius
            self.mass = mass

In some other cases, ‘None’ is a valid value for the caller to set, and
so cannot be used as a sentinel to distinguish the default. For those
cases, creating a specific object instance to serve as the sentinel is
simple and clear:

    class Foo:

        _SENTINEL = object()

        def __init__(centre=(0, 0), radius=_SENTINEL, mass=_SENTINEL):
            if radius is _SENTINEL:
                # Caller didn't specify. Set a default value.
                radius = 10
            if mass is _SENTINEL:
                # Caller didn't specify. Set a default value.
                mass = 1
            self.centre = centre
            self.radius = radius
            self.mass = mass

Creating a new object specifically for the sentinel means there is no
chance some other value will compare identical. Choosing a
leading-underscore name indicates to the reader that this is not part of
the public API.

-- 
 \        “Odious ideas are not entitled to hide from criticism behind |
  `\       the human shield of their believers' feelings.” —Richard M. |
_o__)                                                         Stallman |
Ben Finney

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web