• Configuring an object via a dictionary

    From Loris Bennett@21:1/5 to All on Fri Mar 15 10:30:03 2024
    Hi,

    I am initialising an object via the following:

    def __init__(self, config):

    self.connection = None

    self.source_name = config['source_name']
    self.server_host = config['server_host']
    self.server_port = config['server_port']
    self.user_base = config['user_base']
    self.user_identifier = config['user_identifier']
    self.group_base = config['group_base']
    self.group_identifier = config['group_identifier']
    self.owner_base = config['owner_base']

    However, some entries in the configuration might be missing. What is
    the best way of dealing with this?

    I could of course simply test each element of the dictionary before
    trying to use. I could also just write

    self.config = config

    but then addressing the elements will add more clutter to the code.

    However, with a view to asking forgiveness rather than
    permission, is there some simple way just to assign the dictionary
    elements which do in fact exist to self-variables?

    Or should I be doing this completely differently?

    Cheers,

    Loris

    --
    This signature is currently under constuction.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mats Wichmann@21:1/5 to Loris Bennett via Python-list on Fri Mar 15 12:35:26 2024
    On 3/15/24 03:30, Loris Bennett via Python-list wrote:
    Hi,

    I am initialising an object via the following:

    self.source_name = config['source_name']

    config.get('source_name', default_if_not_defined) is a common technique...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tobiah@21:1/5 to Loris Bennett on Fri Mar 15 11:59:20 2024
    On 3/15/24 02:30, Loris Bennett wrote:
    Hi,

    I am initialising an object via the following:

    def __init__(self, config):

    self.connection = None

    self.source_name = config['source_name']
    self.server_host = config['server_host']

    However, with a view to asking forgiveness rather than
    permission, is there some simple way just to assign the dictionary
    elements which do in fact exist to self-variables?

    class Foo():

    def __init__(self, config):

    for key, val in config.iteritems():
    setattr(self, key, val)

    f = Foo({'cat': 'dog'})

    print(f.cat)

    (outputs 'dog')

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Loris Bennett via Python-list on Fri Mar 15 14:45:21 2024
    On 3/15/2024 5:30 AM, Loris Bennett via Python-list wrote:
    Hi,

    I am initialising an object via the following:

    def __init__(self, config):

    self.connection = None

    self.source_name = config['source_name']
    self.server_host = config['server_host']
    self.server_port = config['server_port']
    self.user_base = config['user_base']
    self.user_identifier = config['user_identifier']
    self.group_base = config['group_base']
    self.group_identifier = config['group_identifier']
    self.owner_base = config['owner_base']

    However, some entries in the configuration might be missing. What is
    the best way of dealing with this?

    I could of course simply test each element of the dictionary before
    trying to use. I could also just write

    self.config = config

    but then addressing the elements will add more clutter to the code.

    However, with a view to asking forgiveness rather than
    permission, is there some simple way just to assign the dictionary
    elements which do in fact exist to self-variables?

    Or should I be doing this completely differently?

    self.source_name = config.get('source_name', default_value)

    Or, if you like this kind of expression better,

    self.source_name = config.get('source_name') or default_value

    .get() will return None if the key doesn't exist, or the default value
    if you specify one.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Grant Edwards via Python-list on Fri Mar 15 15:48:17 2024
    On 3/15/2024 3:09 PM, Grant Edwards via Python-list wrote:
    On 2024-03-15, Thomas Passin via Python-list <python-list@python.org> wrote:
    On 3/15/2024 5:30 AM, Loris Bennett via Python-list wrote:
    Hi,

    I am initialising an object via the following:

    def __init__(self, config):

    self.connection = None

    self.source_name = config['source_name']
    self.server_host = config['server_host']
    self.server_port = config['server_port']
    self.user_base = config['user_base']
    self.user_identifier = config['user_identifier']
    self.group_base = config['group_base']
    self.group_identifier = config['group_identifier']
    self.owner_base = config['owner_base']

    However, some entries in the configuration might be missing. What is
    the best way of dealing with this?

    I could of course simply test each element of the dictionary before
    trying to use. I could also just write

    self.config = config

    but then addressing the elements will add more clutter to the code.

    However, with a view to asking forgiveness rather than
    permission, is there some simple way just to assign the dictionary
    elements which do in fact exist to self-variables?

    Or should I be doing this completely differently?

    self.source_name = config.get('source_name', default_value)

    Or, if you like this kind of expression better,

    self.source_name = config.get('source_name') or default_value

    Won't the latter version misbehave if the value of config['source_name'] has a
    "false" boolean value (e.g. "", 0, 0.0, None, [], (), {}, ...)

    config = {}
    config['source_name'] = ""
    config.get('source_name') or 'default'
    'default'

    Oh, well, picky, picky! I've always like writing using the "or" form
    and have never gotten bit - especially for configuration-type values
    where you really do expect a non-falsey value, it's probably low risk -
    but of course, you're right. In newer code I have been putting a default
    into get(). And I suppose there is always the possibility that sometime
    in the future an "or" clause like that will be changed to return a
    Boolean, which one would expect anyway.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tobiah@21:1/5 to All on Fri Mar 15 12:22:30 2024
    I should mention that I wanted to answer your question,
    but I wouldn't actually do this. I'd rather opt for
    your self.config = config solution. The config options
    should have their own namespace.

    I don't mind at all referencing foo.config['option'],
    or you could make foo.config an object by itself so
    you can do foo.config.option. You'd fill it's attributes
    in the same way I suggested for your main object.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to Loris Bennett on Fri Mar 15 21:09:25 2024
    On Fri, 15 Mar 2024 10:30:03 +0100, Loris Bennett wrote:

    self.source_name = config['source_name']
    self.server_host = config['server_host']
    self.server_port = config['server_port']
    self.user_base = config['user_base']
    self.user_identifier = config['user_identifier']
    self.group_base = config['group_base']
    self.group_identifier = config['group_identifier']
    self.owner_base = config['owner_base']

    However, some entries in the configuration might be missing.

    Since all the attribute names and dictionary keys are the same, the
    solution is simple:

    for k in \
    (
    'source_name',
    'server_host',
    'server_port',
    'user_base',
    'user_identifier',
    'group_base',
    'group_identifier',
    'owner_base',
    ) \
    :
    if k in config :
    setattr(self, k, config[k])
    #end if
    #end for

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From 2QdxY4RzWzUUiLuE@potatochowder.com@21:1/5 to Thomas Passin via Python-list on Fri Mar 15 17:33:09 2024
    On 2024-03-15 at 15:48:17 -0400,
    Thomas Passin via Python-list <python-list@python.org> wrote:

    [...] And I suppose there is always the possibility that sometime in
    the future an "or" clause like that will be changed to return a
    Boolean, which one would expect anyway.

    Not only is the current value is way more useful, but changing it would
    be a compatibility and maintenance nightmare.

    If I want Java, I know where to find it. :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Dan Sommers via Python-list on Fri Mar 15 19:08:23 2024
    On 3/15/2024 5:33 PM, Dan Sommers via Python-list wrote:
    On 2024-03-15 at 15:48:17 -0400,
    Thomas Passin via Python-list <python-list@python.org> wrote:

    [...] And I suppose there is always the possibility that sometime in
    the future an "or" clause like that will be changed to return a
    Boolean, which one would expect anyway.

    Not only is the current value is way more useful, but changing it would
    be a compatibility and maintenance nightmare.

    I'm with you here!

    If I want Java, I know where to find it. :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dn@21:1/5 to Loris Bennett via Python-list on Sat Mar 16 11:23:38 2024
    On 15/03/24 22:30, Loris Bennett via Python-list wrote:
    Hi,

    I am initialising an object via the following:

    def __init__(self, config):

    self.connection = None

    self.source_name = config['source_name']
    self.server_host = config['server_host']
    self.server_port = config['server_port']
    self.user_base = config['user_base']
    self.user_identifier = config['user_identifier']
    self.group_base = config['group_base']
    self.group_identifier = config['group_identifier']
    self.owner_base = config['owner_base']

    However, some entries in the configuration might be missing. What is
    the best way of dealing with this?

    How do you define "missing"?

    Thus, @Thomas' suggestion may/not apply. It is neat and easy.

    I usually plump for:

    self.source_name = config[ "source_name" ] or default_value

    but @Grant's warning applies!
    (which is why the pythonic way is to use (and test for) None as a
    definition of "missing" (see also impacts of using default values and
    mutable data-structures)


    LBYL cf EAFP:
    When setting-up an environment like this, elements are often set to a default-value, and then user-settings, command-line arguments, and the
    like, applied in a priority-order sequence, amend as-appropriate. In
    this way, such problems will never arise.

    This is the better course 90% of the time.


    Which raises the next question:

    What is the impact if some attribute is "missing"? ie if the 'whatever'
    must be identified by source_name (for example), then there is little
    point in assigning any values to the new class. Considerations which
    apply *after* this question, the __init__(), are at least
    equally-important considerations (see below)!


    I could of course simply test each element of the dictionary before
    trying to use. I could also just write

    self.config = config

    but then addressing the elements will add more clutter to the code.

    By which you mean that such "clutter" should only appear in the
    __init__() - which is not such a bad idea (but see below).

    OTOH it is often helpful to one's comprehension to be given a prompt as
    to the source of the data. Thus, in later processing *config[
    "source_name" ] may add a small amount of extra information to the
    reader, over self.source_name.

    * maybe prepended "self.", or not...


    Am assuming that passing all eight elements as individual arguments is off-the-table, embodying far too many 'negatives' (see below).


    However, with a view to asking forgiveness rather than
    permission, is there some simple way just to assign the dictionary
    elements which do in fact exist to self-variables?

    Assuming config is a dict:

    self.__dict__.update( config )

    will work, but attracts similar criticism - if not "clutter" then an unnecessary view (and understanding) of the workings of classes
    under-the-hood.


    Another question:
    When these values are used, are they all used at the same time, and
    never again? It may only be worth 'breaking-out' and making attributes
    from those which are used in multiple situations within the class's
    methods. If, the other extreme, they are only (effectively) passed from
    the __init__() to some sort of open() method, then pass the
    data-structure as an whole and delegate/remove the "clutter" to there.
    In that scenario, such detail would *only* has meaning *and* purpose in
    the open() method and thus no point in cluttering-up the __init__() with
    detail that is only required elsewhere!


    Or should I be doing this completely differently?

    YMMV, but I prefer the idea of transferring the environment/config as a
    whole (as above).

    If it were a class (cf the supposed dict) then "clutter" is reduced by eschewing brackets and quotation-marks, eg "config.source_name".


    If those eight-elements are not the entirety of that data-structure,
    then consider creating an interface-class, which is extracted (or built
    that way) from some wider 'environment', and used to set-up access to data-source(s) or whatever. Again, this aids understanding in knowing
    where data has been created/gathered, and improves confidence when
    utilising it down-the-line.

    The other principle in only providing the required (eight) items of
    data, is that the 'receiving-class' needs no understanding of the
    structure or workings of the 'sending-class' = separation of concerns,
    and each class has single purpose/reason to change.


    A variation on that might be to use a method/function as the interface:

    access = Access( config.access_data )

    Thus, the config class (instance) will need an access_data method to
    collate the data-items. The complimentary code in this Access.__init__(
    self, config, ) might be something like:

    (
    self.source_name,
    self.server_host,
    self.server_port,
    self.user_base,
    self.user_identifier,
    self.group_base,
    self.group_identifier,
    self.owner_base = config_access()
    )

    If you know my style/preferences, notice that I'm breaking my own 'rule'
    of using named-parameters in preference to positional-parameters when
    there are three or more. However, this *may* be one of those exceptions
    (cf hobgoblins). That said, this is the third and least-preferred idea!

    --
    Regards,
    =dn

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Barry@21:1/5 to All on Sat Mar 16 08:15:19 2024
    On 15 Mar 2024, at 19:51, Thomas Passin via Python-list <python-list@python.org> wrote:

    I've always like writing using the "or" form and have never gotten bit

    I, on the other hand, had to fix a production problem that using “or” introducted.
    I avoid this idiom because it fails on falsy values.

    Barry

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Roel Schroeven@21:1/5 to Barry via Python-list on Sat Mar 16 13:12:58 2024
    Barry via Python-list schreef op 16/03/2024 om 9:15:

    On 15 Mar 2024, at 19:51, Thomas Passin via Python-list <python-list@python.org> wrote:

    I've always like writing using the "or" form and have never gotten bit

    I, on the other hand, had to fix a production problem that using “or” introducted.
    I avoid this idiom because it fails on falsy values.

    Me too. It's just too fragile. When writing code you're going to need an alternative for cases where "config.get('source_name') or default_value" doesn't work correctly; much better to use that alternative for all cases.

    --
    "This planet has - or rather had - a problem, which was this: most of the people living on it were unhappy for pretty much of the time. Many solutions were suggested for this problem, but most of these were largely concerned with the movement of small green pieces of paper, which was odd because on the whole it wasn't the small green pieces of paper that were unhappy."
    -- Douglas Adams

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Roel Schroeven via Python-list on Sat Mar 16 09:02:56 2024
    On 3/16/2024 8:12 AM, Roel Schroeven via Python-list wrote:
    Barry via Python-list schreef op 16/03/2024 om 9:15:

    On 15 Mar 2024, at 19:51, Thomas Passin via Python-list
    <python-list@python.org>  wrote:
    I've always like writing using the "or" form and have never gotten
    bit

    I, on the other hand, had to fix a production problem that using “or”
    introducted.
    I avoid this idiom because it fails on falsy values.

    Me too. It's just too fragile. When writing code you're going to need an alternative for cases where "config.get('source_name') or default_value" doesn't work correctly; much better to use that alternative for all cases.

    Trying to remember when I've used it, that was probably on personal code
    where I had a good idea what the values could be. Otherwise, I'm in
    agreement.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dn@21:1/5 to Barry via Python-list on Sun Mar 17 10:19:10 2024
    On 16/03/24 21:15, Barry via Python-list wrote:


    On 15 Mar 2024, at 19:51, Thomas Passin via Python-list <python-list@python.org> wrote:

    I've always like writing using the "or" form and have never gotten bit

    I, on the other hand, had to fix a production problem that using “or” introducted.
    I avoid this idiom because it fails on falsy values.

    As with any other facility, one has to understand ALL implications!

    It must be one of those intensely-frustrating errors to track-down,
    which is then oh-so-simple to fix!

    Are you able to list (real, if suitably anonymised) examples of where
    the truthy/falsy was inappropriate, please?

    --
    Regards,
    =dn

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter J. Holzer@21:1/5 to Barry via Python-list on Sun Mar 17 00:06:06 2024
    On 2024-03-16 08:15:19 +0000, Barry via Python-list wrote:
    On 15 Mar 2024, at 19:51, Thomas Passin via Python-list <python-list@python.org> wrote:
    I've always like writing using the "or" form and have never gotten bit

    I, on the other hand, had to fix a production problem that using “or” introducted.
    I avoid this idiom because it fails on falsy values.

    Perl has a // operator (pronounced "err"), which works like || (or),
    except that it tests whether the left side is defined (not None in
    Python terms) instead of truthy. This still isn't bulletproof but I've
    found it very handy.

    hp

    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ | challenge!"

    -----BEGIN PGP SIGNATURE-----

    iQIzBAABCgAdFiEETtJbRjyPwVTYGJ5k8g5IURL+KF0FAmX2JdkACgkQ8g5IURL+ KF0gQQ/+K1gdCHUuqhhsOphpGtwXRiDJOan8Jy19pwQO9cABv5c8JMGbzLpRSAw5 9r0NIBvIVRBcCQS45h4Cal3RsrfrqHgQfNvrY8utq55RGMlLxcqrg6dCyLeeR8Qn j+TCco/psKdsLIhyHMUuhRn83r0pC70lXqrkuI/lcXYuzbnKNUs4a5lEBKILqvP+ 22a0rOzw/SbLdHunDUFoG24tcDqWCX/qrZmcgxD3/z0sncbC8Z4vK2n3s0MgUfap 0KUQ0qQi9MYiA/O6cbKBs+4JxzxU8H3/9MfkMQ7xaioXPqKJlfhcgN2IvkRjACox B8C8cReAwXvjchQYuZpFibJxvEm9b0MZF/BIv8Rwln2wqy8dIpCX1ggMkTmIwLX1 4UNhLvRuwLCywzosYMllKv1F4PMBexpOzzjTHvHpBu10kEVLzN7+ivOt31sRSIHR O+F3fR5i+DTC/q0p0ZUVN3AJy+wOryNSiRjcf+CNO3aj6976FXir5GApc1JZIiBb IhNzamzrPijCClig8HUT2ddEvoq4gYCA9wgiMi1/6P0bz1m19Dm/z90sPNfkYRlh poVy7SV1QuHfDS5+rAyLp2Rgt2pPao+EqT74VbGUDwtpAeN3tg/tE0KF4YcctOxB 5smbXIACTVQD3F2V3qbKpUUV5bbQQZRz5LMp8vA
  • From dn@21:1/5 to Peter J. Holzer via Python-list on Sun Mar 17 17:15:32 2024
    On 17/03/24 12:06, Peter J. Holzer via Python-list wrote:
    On 2024-03-16 08:15:19 +0000, Barry via Python-list wrote:
    On 15 Mar 2024, at 19:51, Thomas Passin via Python-list <python-list@python.org> wrote:
    I've always like writing using the "or" form and have never gotten bit

    I, on the other hand, had to fix a production problem that using “or” introducted.
    I avoid this idiom because it fails on falsy values.

    Perl has a // operator (pronounced "err"), which works like || (or),
    except that it tests whether the left side is defined (not None in
    Python terms) instead of truthy. This still isn't bulletproof but I've
    found it very handy.


    So, if starting from:

    def method( self, name=None, ):

    rather than:

    self.name = name if name else default_value

    ie

    self.name = name if name is True else default_value


    the more precise:

    self.name = name if name is not None or default_value

    or:

    self.name = default_value if name is None or name

    because "is" checks for identity, whereas "==" and True-thy encompass a
    range of possible alternate values?

    --
    Regards,
    =dn

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter J. Holzer@21:1/5 to dn via Python-list on Sun Mar 17 16:11:53 2024
    On 2024-03-17 17:15:32 +1300, dn via Python-list wrote:
    On 17/03/24 12:06, Peter J. Holzer via Python-list wrote:
    On 2024-03-16 08:15:19 +0000, Barry via Python-list wrote:
    On 15 Mar 2024, at 19:51, Thomas Passin via Python-list <python-list@python.org> wrote:
    I've always like writing using the "or" form and have never gotten bit

    I, on the other hand, had to fix a production problem that using “or” introducted.
    I avoid this idiom because it fails on falsy values.

    Perl has a // operator (pronounced "err"), which works like || (or),
    except that it tests whether the left side is defined (not None in
    Python terms) instead of truthy. This still isn't bulletproof but I've found it very handy.


    So, if starting from:

    def method( self, name=None, ):

    rather than:

    self.name = name if name else default_value

    ie

    self.name = name if name is True else default_value

    These two lines don't have the same meaning (for the reason you outlined below). The second line is also not very useful.



    the more precise:

    self.name = name if name is not None or default_value

    or:

    self.name = default_value if name is None or name

    Those are syntax errors. I think you meant to write "else" instead of
    "or".

    Yes, exactly. That's the semantic of Perl's // operator.

    JavaScript has a ?? operator with similar semantics (slightly
    complicated by the fact that JavaScript has two "nullish" values).

    hp

    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ | challenge!"

    -----BEGIN PGP SIGNATURE-----

    iQIzBAABCgAdFiEETtJbRjyPwVTYGJ5k8g5IURL+KF0FAmX3CDQACgkQ8g5IURL+ KF31jQ//ZwV92D/zxhfiyNPtpByOT5Wg4NaV1YKhMKquaW0++938DacHzUJzCbwa r9ZfbixAkNn1WRROi6+x9iv7zFnk5CJWggDLFQJgAmlLgWKgW1RTOEhRFEekkqDc lNvW7GKHRtqEIUnywmWsIW8I0Fz4QLZwDwtjet6Or2sI9k3T5q7uEKxUQLhW6eAY TEDFbH6jBA0UeSyX/7s6tMeycTAk3DKsxu0HAHwBxli0AP17wCgsuhkhebOtuB3O KKDkE36hd4DLi52nlAzYX6+jUgPZE3iMJg6P7wNFtGgsVS6HfnK9LqL7AaiUUxzf VYlLmQMdBN1Tn3N5YGIrZ744fsqyVmEaayaY6n3ta7fwrcoC3pGJ0C6IiN26Ituy m2JX5RVrM6jUwaMkdHSHILn+QZdurWf6JAyHiv68J0lS6P7A27bRX4OIdJBoA2UV HTd1inxabevporT+6ImW1NT7mAzDGYvK6FfVebS4vEi55oBZtn9nM0McRAqOGBF2 ZExgpHgLItgKkYlGGc0djv7adun3+KNx91aGauyHF6uMc7pb5gGmsBr409B0tNVU gra81kg4eI6xU0wUqY1wX8nXmA3mhjRsKn+GUbFkXx7xhwppV8N2wocd5K+I4N2W EEfXA7ThEEikxGa2V7DVriMT7ppQ7POhgwKlM8u
  • From dn@21:1/5 to Peter J. Holzer via Python-list on Mon Mar 18 10:09:27 2024
    On 18/03/24 04:11, Peter J. Holzer via Python-list wrote:
    On 2024-03-17 17:15:32 +1300, dn via Python-list wrote:
    On 17/03/24 12:06, Peter J. Holzer via Python-list wrote:
    On 2024-03-16 08:15:19 +0000, Barry via Python-list wrote:
    On 15 Mar 2024, at 19:51, Thomas Passin via Python-list <python-list@python.org> wrote:
    I've always like writing using the "or" form and have never gotten bit >>>>
    I, on the other hand, had to fix a production problem that using “or” introducted.
    I avoid this idiom because it fails on falsy values.

    Perl has a // operator (pronounced "err"), which works like || (or),
    except that it tests whether the left side is defined (not None in
    Python terms) instead of truthy. This still isn't bulletproof but I've
    found it very handy.


    So, if starting from:

    def method( self, name=None, ):

    rather than:

    self.name = name if name else default_value

    ie

    self.name = name if name is True else default_value

    These two lines don't have the same meaning (for the reason you outlined below). The second line is also not very useful.



    the more precise:

    self.name = name if name is not None or default_value

    or:

    self.name = default_value if name is None or name

    Those are syntax errors. I think you meant to write "else" instead of
    "or".

    Yes, exactly. That's the semantic of Perl's // operator.

    JavaScript has a ?? operator with similar semantics (slightly
    complicated by the fact that JavaScript has two "nullish" values).


    Thanks Peter!
    (yes, sad consequences of suffering a neighbor's party-til-midnight
    followed by an 0530 meeting-start - children: don't code exhausted!)


    Herewith, an illustration of how the corrected version of the above
    works - and how (in what seem unusual cases) it avoids any truthy/falsy confusion, as raised earlier in this thread:

    default_value = "default"
    name = "Fred Flintstone"
    name if name is not None else default_value
    'Fred Flintstone'

    name = None
    name if name is not None else default_value
    'default'
    name = False
    name if name is not None else default_value
    False
    name = 1
    name if name is not None else default_value
    1
    name = 0
    name if name is not None else default_value
    0


    Personally: I find the above coding more logical, because our primary
    interest is on 'the happy case', ie where the value has been assigned
    (to "name"); and the default_value is only applied as a "guard".


    On the other hand, I dislike the not-condition because it forces me to
    think (and maybe dust-off DeMorgan). Accordingly:

    name = "Fred Flintstone"
    default_value if name is None else name
    'Fred Flintstone'
    name = None
    default_value if name is None else name
    'default'
    name = False
    default_value if name is None else name
    False
    ...


    YMMV!
    NB your corporate Style Guide may prefer 'the happy path'...

    --
    Regards,
    =dn

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Loris Bennett@21:1/5 to Tobiah on Mon Mar 18 07:42:32 2024
    Tobiah <toby@tobiah.org> writes:

    I should mention that I wanted to answer your question,
    but I wouldn't actually do this. I'd rather opt for
    your self.config = config solution. The config options
    should have their own namespace.

    I don't mind at all referencing foo.config['option'],
    or you could make foo.config an object by itself so
    you can do foo.config.option. You'd fill it's attributes
    in the same way I suggested for your main object.

    Thanks for the thoughts. I'll go for self.config = config after
    all, since, as you say, the clutter caused by the referencing is not
    that significant.

    Cheers,

    Loris

    --
    This signature is currently under constuction.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Anders Munch@21:1/5 to All on Mon Mar 18 13:57:57 2024
    dn wrote:
    Loris Bennett wrote:
    However, with a view to asking forgiveness rather than
    permission, is there some simple way just to assign the dictionary
    elements which do in fact exist to self-variables?

    Assuming config is a dict:

    self.__dict__.update( config )

    Here's another approach:

    config_defaults = dict(
    server_host='localhost',
    server_port=443,
    # etc.
    )
    ...
    def __init__(self, config):
    self.conf = types.SimpleNamespace(**{**config_defaults, **config})

    This gives you defaults, simple attribute access, and avoids the risk of name collisions that you get when updating __dict__.

    Using a dataclass may be better:

    @dataclasses.dataclass
    class Settings:
    group_base : str
    server_host : str = 'localhost'
    server_port : int = 443
    ...
    def __init__(self, config):
    self.conf = Settings(**config)

    regards, Anders

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Gilmeh Serda@21:1/5 to All on Mon Mar 18 23:44:51 2024
    On Mon, 18 Mar 2024 10:09:27 +1300, dn wrote:

    YMMV!
    NB your corporate Style Guide may prefer 'the happy path'...

    If you only want to check for None, this works too:

    name = None
    dafault_value = "default"
    name or default_value
    'default'
    name = 'Fred Flintstone'
    name or default_value
    'Fred Flintstone'

    --
    Gilmeh

    A little suffering is good for the soul. -- Kirk, "The Corbomite
    Maneuver", stardate 1514.0

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Roel Schroeven@21:1/5 to All on Wed Mar 20 09:49:54 2024
    Op 19/03/2024 om 0:44 schreef Gilmeh Serda via Python-list:
    On Mon, 18 Mar 2024 10:09:27 +1300, dn wrote:

    YMMV!
    NB your corporate Style Guide may prefer 'the happy path'...

    If you only want to check for None, this works too:

    name = None
    dafault_value = "default"
    name or default_value
    'default'
    name = 'Fred Flintstone'
    name or default_value
    'Fred Flintstone'

    name = ''
    name or default_value
    'default'

    name = False
    name or default_value
    'default'

    name = []
    name or default_value
    'default'

    name = 0
    name or default_value
    'default'

    You haven't only checked for None! You have rejected *every* falsish
    value, even though they may very well be acceptable values.

    --
    "Most of us, when all is said and done, like what we like and make up
    reasons for it afterwards."
    -- Soren F. Petersen

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From 2QdxY4RzWzUUiLuE@potatochowder.com@21:1/5 to Roel Schroeven via Python-list on Wed Mar 20 05:28:24 2024
    On 2024-03-20 at 09:49:54 +0100,
    Roel Schroeven via Python-list <python-list@python.org> wrote:

    You haven't only checked for None! You have rejected *every* falsish value, even though they may very well be acceptable values.

    OTOH, only you can answer these questions about your situations.

    Every application, every item of configuration data, is going to be a
    little bit different.

    What, exactly, does "missing" mean? That there's no entry in a config
    file? That there's some sort of degenerate entry with "missing"
    semantics (e.g. a line in a text file that contains the name of the
    value and an equals sign, but no value)? An empty string or list? Are
    you making your program easier for users to use, easier for testers to
    test, easier for authors to write and to maintain, or something else?
    What is your program allowed and not allowed to do in the face of
    "missing" configuration data?

    Once you've nailed down the semantics of the configuration data, then
    the code usually falls out pretty quickly. But arguing about corner
    cases and failure modes without specifications is a losing battle.
    Every piece of code is suspect unless you know what the inputs mean, and
    what the application "should" do if the don't look like that.

    Python's flexibiliry and expressiveness are double edge swords. Use
    them wisely. :-)

    Sorry for the rant.

    Carry on.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)