• Addition of a .= operator

    From Alex Jando@21:1/5 to All on Sat May 20 10:54:59 2023
    I have many times had situations where I had a variable of a certain type, all I cared about it was one of it's methods.

    For example:

    ------------------------------------------------------------
    import hashlib
    hash = hashlib.sha256(b'word')
    hash = hash.hexdigest() ------------------------------------------------------------
    import enum
    class Number(enum.Enum):
    One: int = 1
    Two: int = 2
    Three: int = 3
    num = Number.One
    num = num.value
    ------------------------------------------------------------

    Now to be fair, in the two situations above, I could just access the method right as I declare the object, however, sometimes when passing values into functions, it's a lot messier to do that.

    So what I'm suggesting is something like this:

    ------------------------------------------------------------
    import hashlib
    hash = hashlib.sha256(b'word')
    hash.=hexdigest()
    ------------------------------------------------------------
    import enum
    class Number(enum.Enum):
    One: int = 1
    Two: int = 2
    Three: int = 3
    num = Number.One
    num.=value
    ------------------------------------------------------------

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dn@21:1/5 to Alex Jando on Sun May 21 06:11:02 2023
    On 21/05/2023 05.54, Alex Jando wrote:
    I have many times had situations where I had a variable of a certain type, all I cared about it was one of it's methods.

    For example:

    ------------------------------------------------------------
    import hashlib
    hash = hashlib.sha256(b'word')
    hash = hash.hexdigest() ------------------------------------------------------------
    import enum
    class Number(enum.Enum):
    One: int = 1
    Two: int = 2
    Three: int = 3
    num = Number.One
    num = num.value
    ------------------------------------------------------------

    Now to be fair, in the two situations above, I could just access the method right as I declare the object, however, sometimes when passing values into functions, it's a lot messier to do that.

    So what I'm suggesting is something like this:

    ------------------------------------------------------------
    import hashlib
    hash = hashlib.sha256(b'word')
    hash.=hexdigest() ------------------------------------------------------------
    import enum
    class Number(enum.Enum):
    One: int = 1
    Two: int = 2
    Three: int = 3
    num = Number.One
    num.=value
    ------------------------------------------------------------

    A custom-class wrapper?
    Even, a decorator-able function?

    --
    Regards,
    =dn

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From 2QdxY4RzWzUUiLuE@potatochowder.com@21:1/5 to dn via Python-list on Sat May 20 14:48:34 2023
    On 2023-05-21 at 06:11:02 +1200,
    dn via Python-list <python-list@python.org> wrote:

    On 21/05/2023 05.54, Alex Jando wrote:
    I have many times had situations where I had a variable of a certain type, all I cared about it was one of it's methods.

    For example:

    ------------------------------------------------------------
    import hashlib
    hash = hashlib.sha256(b'word')
    hash = hash.hexdigest() ------------------------------------------------------------
    import enum
    class Number(enum.Enum):
    One: int = 1
    Two: int = 2
    Three: int = 3
    num = Number.One
    num = num.value ------------------------------------------------------------

    Now to be fair, in the two situations above, I could just access the method right as I declare the object, however, sometimes when passing values into functions, it's a lot messier to do that.

    Can you give an example, preferably one from an actual program, that
    shows the mess? Is it More Messier™ than the difference between the following examples?

    # example 1
    hash = hashlib.sha256(b'word')
    f(hash.hexdigest()) # call f with hash's hexdigest

    # example 2
    hash = hashlib.sha256(b'word')
    hash = hash.hexdigest() # extract hash's hexdigest
    f(hash) # call f with hash's hexdigest

    Can you also show what your code would look like with a .= operator?

    So what I'm suggesting is something like this:

    ------------------------------------------------------------
    import hashlib
    hash = hashlib.sha256(b'word')
    hash.=hexdigest() ------------------------------------------------------------
    import enum
    class Number(enum.Enum):
    One: int = 1
    Two: int = 2
    Three: int = 3
    num = Number.One
    num.=value
    ------------------------------------------------------------

    A custom-class wrapper?
    Even, a decorator-able function?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From avi.e.gross@gmail.com@21:1/5 to dn via Python-list on Sat May 20 15:52:54 2023
    I would suggest thinking carefully about ramifications as well as any benefits of adding some or .=operator.

    It sounds substantially different than the whole slew of +=, *= and so on types of operators. The goal some would say of those is to either allow the interpreter optimize by not evaluating twice as in x = x + 1 or python extensions of the dunder type
    like __iadd__() that allow you to control what exactly is done and which sometimes make a += b do things a bit different than a= a+b.

    So what would a __i_invoke_method__() function look like? It seems you want the command to sort of replace
    Object = Object.method(args)

    But for any method whatsoever.

    But Python objects can have methods all over the place as they may be subclasses that inherit methods, or may implement an abstract method or use multiple inheritance. All that searching happens in the current way, so if

    Object.method(args))

    Works as expected, would your new method be just syntactic sugar, or would it look for a dunder method that may have no idea initially what you want?

    Just curious.

    Is there an alternative way you could get the functionality without using the same way that is used for a very different circumstance?


    -----Original Message-----
    From: Python-list <python-list-bounces+avi.e.gross=gmail.com@python.org> On Behalf Of 2QdxY4RzWzUUiLuE@potatochowder.com
    Sent: Saturday, May 20, 2023 2:49 PM
    To: python-list@python.org
    Subject: Re: Addition of a .= operator

    On 2023-05-21 at 06:11:02 +1200,
    dn via Python-list <python-list@python.org> wrote:

    On 21/05/2023 05.54, Alex Jando wrote:
    I have many times had situations where I had a variable of a certain type, all I cared about it was one of it's methods.

    For example:

    ------------------------------------------------------------
    import hashlib
    hash = hashlib.sha256(b'word')
    hash = hash.hexdigest() ------------------------------------------------------------
    import enum
    class Number(enum.Enum):
    One: int = 1
    Two: int = 2
    Three: int = 3
    num = Number.One
    num = num.value ------------------------------------------------------------

    Now to be fair, in the two situations above, I could just access the method right as I declare the object, however, sometimes when passing values into functions, it's a lot messier to do that.

    Can you give an example, preferably one from an actual program, that
    shows the mess? Is it More Messier™ than the difference between the following examples?

    # example 1
    hash = hashlib.sha256(b'word')
    f(hash.hexdigest()) # call f with hash's hexdigest

    # example 2
    hash = hashlib.sha256(b'word')
    hash = hash.hexdigest() # extract hash's hexdigest
    f(hash) # call f with hash's hexdigest

    Can you also show what your code would look like with a .= operator?

    So what I'm suggesting is something like this:

    ------------------------------------------------------------
    import hashlib
    hash = hashlib.sha256(b'word')
    hash.=hexdigest() ------------------------------------------------------------
    import enum
    class Number(enum.Enum):
    One: int = 1
    Two: int = 2
    Three: int = 3
    num = Number.One
    num.=value
    ------------------------------------------------------------

    A custom-class wrapper?
    Even, a decorator-able function?
    --
    https://mail.python.org/mailman/listinfo/python-list

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter J. Holzer@21:1/5 to Alex Jando on Sat May 20 22:15:24 2023
    On 2023-05-20 10:54:59 -0700, Alex Jando wrote:
    I have many times had situations where I had a variable of a certain
    type, all I cared about it was one of it's methods.

    For example:

    ------------------------------------------------------------
    hash = hash.hexdigest() ------------------------------------------------------------
    num = num.value
    ------------------------------------------------------------

    So what I'm suggesting is something like this:

    ------------------------------------------------------------ hash.=hexdigest() ------------------------------------------------------------
    num.=value
    ------------------------------------------------------------

    I actually needed to read those twice to get their meaning. I think

    hash .= hexdigest()
    num .= value

    would have been clearer (yes, I nag my colleagues about white-space,
    too).

    Do you have any examples (preferably from real code) where you don't
    assign to a simple variable? I feel that
    x += 1
    isn't much of an improvement over
    x = x + 1
    but
    self.data[line+len(chars)-1] += after
    is definitely an improvement over
    self.data[line+len(chars)-1] + self.data[line+len(chars)-1] + after

    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+KF0FAmRpKlcACgkQ8g5IURL+ KF3hsg/9GcYPI85MipEAN8F/8RNDIjgJKUNtsO7uCXp1dvrazZCI3G+t4gLETJdi RZQLtx33TGB94IitsOdBkYCsBWYbu+0NpD68pScfXs+sMAJn4HM43yg60L6jmAqw iUgJQuMo2T82ZXjfUFRs4lJhY3mIEmhgAXWgdOwx1yHAeIh7AMMSR7k/OPP2rgbs w2gRB0mHiF2Ug1VFOm50JGte2Kbvk16aTDVqmdfNIZ00vRXSHVOWWLoOqGZflR7H kh7u0Xmfuna0w28BMwAMGT8jYQRn157KgeTG4RQd4RleoCEGmSx0jnbqk3ELrmea SNAePb/VGloAUXcllnZgVvuFvFN1WvoWHfqwi6beXLvoNCQZhek5hPu+YUICDmNs RBuZXvLRTW6hRz/6jjrRVefy7I0KyG57qLzuY15nEMJvxfRx2E83ecPh+2dKPjXk doeWLViGWvUYAzg+zGGmHUaLYxMCSUaiWtIS69p5zlzNDSldknMMGsoe5Z6ecAv8 BVuXAa5CDmoh91U1FDSum401Y3Lf4NXP++PLarZMlZnS7LhOZXQXJ4kRC1SeAaQs FcxeobwDoTJvmLhGTVIQs0NdAqY2kHHO9rRhaEaltOGs2CyJTmYkNcHTlpAHOK6w K601BGp94I0ZzlcKtrEa4PlP/OlldHkkQYW7G4s
  • From Richard Damon@21:1/5 to Peter J. Holzer on Sat May 20 17:18:43 2023
    On 5/20/23 4:15 PM, Peter J. Holzer wrote:
    On 2023-05-20 10:54:59 -0700, Alex Jando wrote:
    I have many times had situations where I had a variable of a certain
    type, all I cared about it was one of it's methods.

    For example:

    ------------------------------------------------------------
    hash = hash.hexdigest()
    ------------------------------------------------------------
    num = num.value
    ------------------------------------------------------------

    So what I'm suggesting is something like this:

    ------------------------------------------------------------
    hash.=hexdigest()
    ------------------------------------------------------------
    num.=value
    ------------------------------------------------------------
    I actually needed to read those twice to get their meaning. I think

    hash .= hexdigest()
    num .= value

    would have been clearer (yes, I nag my colleagues about white-space,
    too).

    Do you have any examples (preferably from real code) where you don't
    assign to a simple variable? I feel that
    x += 1
    isn't much of an improvement over
    x = x + 1
    but
    self.data[line+len(chars)-1] += after
    is definitely an improvement over
    self.data[line+len(chars)-1] + self.data[line+len(chars)-1] + after

    hp


    For immutable types, it is just syntactic sugar, but for mutable type
    there is an important difference


    x = []

    y = x

    x += [1]

    changes the list named by y, but

    x = []

    y = x

    x = x + []

    does not.


    The key is that if a type actually implements the inplace operator, then
    using the op= version doesn't bind the name to a new object but mutates
    the object to a new value.

    This just can't happen (as far as I can figure) for .= unless the object
    is defining something weird for the inplace version of the operation,
    which is probably best to not actually allow.

    --
    Richard Damon

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Greg Ewing@21:1/5 to Alex Jando on Sun May 21 12:11:35 2023
    On 21/05/23 5:54 am, Alex Jando wrote:

    hash.=hexdigest()

    That would be a very strange and unprecedented syntax that
    munges together an attribute lookup and a call.

    Keep in mind that a method call in Python is actually two
    separate things:

    y = x.m()

    is equivalent to

    f = x.m
    y = f()

    But it would not be possible to break down your .= syntax
    in that way.

    Another oddity is that these are equivalent:

    x += y
    x += (y)

    i.e. the RHS is evaluated as usual before doing the +=.

    But these would not be equivalent:

    hash .= hexdigest()
    hash .= (hexdigest())

    In fact the latter would probably have to be disallowed, as it's
    not at all clear what it should mean.

    --
    Greg

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Greg Ewing@21:1/5 to Richard Damon on Sun May 21 12:23:30 2023
    On 21/05/23 9:18 am, Richard Damon wrote:
    This just can't happen (as far as I can figure) for .= unless the object
    is defining something weird for the inplace version of the operation,

    Indeed. There are clear use cases for overriding +=, but it's hard to
    think of one for this. So it would just be syntactic sugar, which is
    harder to justify.

    --
    Greg

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rob Cliffe@21:1/5 to Alex Jando on Sun May 21 20:30:45 2023
    On 20/05/2023 18:54, Alex Jando wrote:
    I have many times had situations where I had a variable of a certain type, all I cared about it was one of it's methods.

    For example:

    ------------------------------------------------------------
    import hashlib
    hash = hashlib.sha256(b'word')
    hash = hash.hexdigest() ------------------------------------------------------------
    import enum
    class Number(enum.Enum):
    One: int = 1
    Two: int = 2
    Three: int = 3
    num = Number.One
    num = num.value
    ------------------------------------------------------------

    Now to be fair, in the two situations above, I could just access the method right as I declare the object, however, sometimes when passing values into functions, it's a lot messier to do that.

    So what I'm suggesting is something like this:

    ------------------------------------------------------------
    import hashlib
    hash = hashlib.sha256(b'word')
    hash.=hexdigest() ------------------------------------------------------------
    import enum
    class Number(enum.Enum):
    One: int = 1
    Two: int = 2
    Three: int = 3
    num = Number.One
    num.=value
    ------------------------------------------------------------
    It seems to me that this would encourage bad style.  When you write
        num = num.value
    you are using num with two different meanings (an object and an
    attribute of it).  The original object is lost.
    If down the line you needed to access another attribute of the object,
    you would have to backtrack:
        val = num.value
        spam = num.spam
    or at least write the statements in the right order, so that you only
    overwrite num at the end:
        spam = num.spam
        num = num.value
    Either way, you are making the code more fragile i.e. harder to maintain.
    Now of course, in your use case it may be perfectly appropriate to write
    "num = num.value" as you did.
    But IMO it's not something that should be encouraged in general.
    Best wishes
    Rob Cliffe

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter J. Holzer@21:1/5 to Rob Cliffe via Python-list on Tue May 23 23:03:26 2023
    On 2023-05-21 20:30:45 +0100, Rob Cliffe via Python-list wrote:
    On 20/05/2023 18:54, Alex Jando wrote:
    So what I'm suggesting is something like this:

    ------------------------------------------------------------
    hash = hashlib.sha256(b'word')
    hash.=hexdigest() ------------------------------------------------------------
    num = Number.One
    num.=value
    ------------------------------------------------------------
    It seems to me that this would encourage bad style. When you write
    num = num.value
    you are using num with two different meanings (an object and an
    attribute of it).

    I think that's ok if it's the same thing at a high level.

    I sometimes have a chain of transformations (e.g. first decode it, then
    strip extra spaces, then normalize spelling, then look it up in a
    database and replace it with the record, ...). Technically, of course
    all these intermediate objects are different, and I could make that
    explicit by using different variable names:

    user_param = request.GET["user"]
    user_decoded = str(user_param, encoding="utf-8")
    user_stripped = user_decoded.strip()
    user_normalized = user_stripped.lower()
    user_object = orm.user.get(name=user_normalized)

    But I find it easier to read if I just reuse the same variable name:

    user = request.GET["user"]
    user = str(user, encoding="utf-8")
    user = user.strip()
    user = user.lower()
    user = orm.user.get(name=user)

    Each instance only has a livetime of a single line (or maybe two or
    three lines if I have to combine variables), so there's little risk of confusion, and reusing the variable name makes it very clear that all
    those intermediate results are gone and won't be used again.

    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+KF0FAmRtKhkACgkQ8g5IURL+ KF35nBAApzS3sv4K96W6rZOIOf5ULLqkeRv5HsTzmfdvE8DKwS1bs1BIZtkZIG7H n13fB0IEz5gV1LNs3JlYhNP4+Q37tDmfAXlMxmdPt4Dpby324wxz3F9i+Qp/nzqH Z9dO30C0Jcr6L/DeejR5N9cJpt7HUt4Dx+7h6MEAfLVUnizwAPT2at7yh2IWBwfQ r/KyaUuYdOjvx3ik4FGGtCVdhNth8GjqCofzDwDyHxkP53ok7/HyxzomBufq9fh+ lVqEwHOde0Pt8/ZMfv5rZqj62twjmB7wpEwEGRULmPKVpvr9NhQbMsL2FMVYJgFw c7kJci0gqfVlD/7KX5pfIv4DlES8LhTHwYHD+DZRgB7O/XuSsiG1S5F+5d3tuRFf FKUemCOr2lgl4z4kzF5M1kGaCcpyIc6MPR/fFPsosbO7lOr3yDhlbtDzU3cn1SLs 3aQOvjk8fbyGZWz9tatQPoVamOkgj4FqdxuI7thvBXOABp2Z7O9qzSIJoLvknTim 43LfmR1XIr4ew8waCPjG6LN0Lb/YeNnG3qlxHbVmC4MY8/MRRGUJHoAC7IPFssWU 5c3TrWkDHuOeimTQ1tYhCU6LQ5UAL85U16W6R1p6XdzHF5qxGqwivsOsS8HRG96M cwB3b5BH/1f+pVNKmRQ3vk77xzDXBwsYVCdLBbo
  • From Chris Angelico@21:1/5 to Peter J. Holzer on Wed May 24 07:12:32 2023
    On Wed, 24 May 2023 at 07:04, Peter J. Holzer <hjp-python@hjp.at> wrote:
    But I find it easier to read if I just reuse the same variable name:

    user = request.GET["user"]
    user = str(user, encoding="utf-8")
    user = user.strip()
    user = user.lower()
    user = orm.user.get(name=user)

    Each instance only has a livetime of a single line (or maybe two or
    three lines if I have to combine variables), so there's little risk of confusion, and reusing the variable name makes it very clear that all
    those intermediate results are gone and won't be used again.


    Small side point: You can make use of the bytes object's decode()
    method to make the chaining much more useful here, rather than the
    str() constructor.

    This sort of code might be better as a single expression. For example:

    user = (
    request.GET["user"]
    .decode("utf-8")
    .strip()
    .lower()
    )
    user = orm.user.get(name=user)

    The pipeline is still visible, you've avoided the "user = user ."
    replication, and you've ALSO avoided duplicating "user = " on each
    line too.

    IMO the ".=" syntax would actually be a bit of a nuisance in this
    style of code. Consider how it would look, with your original str
    constructor in the middle:

    user = request.GET["user"]
    user = str(user, encoding="utf-8")
    user .= strip()
    user .= lower()
    user = orm.user.get(name=user)

    The fact that two of them are ".=" rather than "=" is a bit too subtle
    for my liking, possibly because the dot is so small.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rob Cliffe@21:1/5 to All on Tue May 23 23:21:17 2023
    This sort of code might be better as a single expression. For example:

    user = (
    request.GET["user"]
    .decode("utf-8")
    .strip()
    .lower()
    )
    user = orm.user.get(name=user)


    LOL.  And I thought I was the one with a (self-confessed) tendency to
    write too slick, dense, smart-alec code. 😁
    Indeed, I was itching to shorten it (starting with the low-hanging
    fruit: user = user.strip().lower() ).
    Seriously though: this kind of condensation can come unstuck when any of
    the steps need to be made more complicated.
    (Suppose request.GET might return ASCII, might return Unicode, depending
    on which server it was talking to.)
    Peter's actual code feels more Pythonic to me.  (It's even 2 lines
    shorter! 😎)
    Rob Cliffe

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to Rob Cliffe on Wed May 24 08:37:51 2023
    On Wed, 24 May 2023 at 08:22, Rob Cliffe <rob.cliffe@btinternet.com> wrote:


    This sort of code might be better as a single expression. For example:

    user = (
    request.GET["user"]
    .decode("utf-8")
    .strip()
    .lower()
    )
    user = orm.user.get(name=user)


    LOL. And I thought I was the one with a (self-confessed) tendency to
    write too slick, dense, smart-alec code. 😁
    Indeed, I was itching to shorten it (starting with the low-hanging
    fruit: user = user.strip().lower() ).
    Seriously though: this kind of condensation can come unstuck when any of
    the steps need to be made more complicated.
    (Suppose request.GET might return ASCII, might return Unicode, depending
    on which server it was talking to.)

    Do you mean "ASCII or UTF-8"? Because decoding as UTF-8 is fine with
    ASCII (it's a superset). You should always consistently get the same
    data type (bytes or text) based on the library you're using.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to Peter J. Holzer on Wed May 24 08:51:19 2023
    On Wed, 24 May 2023 at 08:48, Peter J. Holzer <hjp-python@hjp.at> wrote:

    On 2023-05-24 07:12:32 +1000, Chris Angelico wrote:
    On Wed, 24 May 2023 at 07:04, Peter J. Holzer <hjp-python@hjp.at> wrote:
    But I find it easier to read if I just reuse the same variable name:

    user = request.GET["user"]
    user = str(user, encoding="utf-8")
    user = user.strip()
    user = user.lower()
    user = orm.user.get(name=user)

    Each instance only has a livetime of a single line (or maybe two or
    three lines if I have to combine variables), so there's little risk of confusion, and reusing the variable name makes it very clear that all those intermediate results are gone and won't be used again.


    Small side point: You can make use of the bytes object's decode()
    method to make the chaining much more useful here, rather than the
    str() constructor.

    This sort of code might be better as a single expression. For example:

    user = (
    request.GET["user"]
    .decode("utf-8")
    .strip()
    .lower()
    )
    user = orm.user.get(name=user)

    Yes, that probably wasn't the best example. I sort of deliberately
    avoided method chaining here to make my point that you don't have to
    invent a new variable name for every intermediate result, but of course
    that backfired because in this case you don't need a variable name at
    all. I should have used regular function calls ...


    In the context of a .= operator, though, that is *in itself* an
    interesting data point: in order to find an example wherein the .=
    operator would be plausible, you had to make the .= operator
    unnecessary.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter J. Holzer@21:1/5 to Chris Angelico on Wed May 24 00:46:38 2023
    On 2023-05-24 07:12:32 +1000, Chris Angelico wrote:
    On Wed, 24 May 2023 at 07:04, Peter J. Holzer <hjp-python@hjp.at> wrote:
    But I find it easier to read if I just reuse the same variable name:

    user = request.GET["user"]
    user = str(user, encoding="utf-8")
    user = user.strip()
    user = user.lower()
    user = orm.user.get(name=user)

    Each instance only has a livetime of a single line (or maybe two or
    three lines if I have to combine variables), so there's little risk of confusion, and reusing the variable name makes it very clear that all
    those intermediate results are gone and won't be used again.


    Small side point: You can make use of the bytes object's decode()
    method to make the chaining much more useful here, rather than the
    str() constructor.

    This sort of code might be better as a single expression. For example:

    user = (
    request.GET["user"]
    .decode("utf-8")
    .strip()
    .lower()
    )
    user = orm.user.get(name=user)

    Yes, that probably wasn't the best example. I sort of deliberately
    avoided method chaining here to make my point that you don't have to
    invent a new variable name for every intermediate result, but of course
    that backfired because in this case you don't need a variable name at
    all. I should have used regular function calls ...

    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+KF0FAmRtQkkACgkQ8g5IURL+ KF0DRg/+KtDfEXmE9YIiSYmECdqQ7KAcGWuaY3ZXYzklLhVNfVN73ODXZ1X9Tx+X orMvRKqTRkqpCFL+InhMAXwR6k3ptDEaCHrys4nlZP/2etj3jux8ZphkPGt0JYKq Oi0wVbWHms7nfWKVifeThLJxDhJ4uFh/04CJJr5UcaItGtpkl46SZ9zOV0gUywOZ 6FXpWJkGxTx/eVCLJTfgxLWxaD+QW11HpiiE4IIgdjAcd+rzf4eUOUovWC7XFjml H84Ab3sJ7qHrWahkVLSwE6cpb/Yjky9dczAtKKMILxQEjgz45NNkri/rfsa+FAR9 dUtzCoba6DbS4yY5LUOV3BldaTBYKKWiPU3OW1p0kuoO6cifpuGJYdKWknbcWs62 Z1MPpkKEygAJBGUsecpcIPJb86U0vLtqi+LFCmKCKn67GmkOQlxVd3Q1QaXoNGbs Pzhbp48SwNQW9E/MeSrrzJ1tlbVb/e8Xc3uR98c9KGs/Z9o5trkIw6hzHS/U+NpC m2cpWV/oUR2kbeWlmeHHf8yuWFFyR/AvW+pKtQGhJ+uC+v5fpVFsGLdXwEvafIdG uDzzpMUQ4UHP9dbFbOYbPJFx5aDm4gBZFpvl0K61IKb9tX9qdPIK35FcDVwUs+Ds XYsXU+eq3ajbZoZaMfJClvqyUorwvA1AMMa7nBx
  • From Chris Angelico@21:1/5 to Rob Cliffe on Wed May 24 09:04:42 2023
    On Wed, 24 May 2023 at 08:57, Rob Cliffe <rob.cliffe@btinternet.com> wrote:
    Do you mean "ASCII or UTF-8"? Because decoding as UTF-8 is fine with
    ASCII (it's a superset). You should always consistently get the same
    data type (bytes or text) based on the library you're using.

    ChrisA
    OK, bad example. The point remains: condensing each step to a single
    chained function can come unstuck when one of the steps needs to be made
    more complicated for some reason.

    That's fair. Still, I wouldn't over-complicate a piece of code "just
    in case" it needs to become more complicated in the future. I'd rather
    code to what's needed now, and if that's a simple "decode as UTF-8",
    that's great; maybe in the future I need to cope with an insane system
    like "decode line by line, attempting UTF-8 first and falling back on Windows-1252, then rejoin the lines", and that's the time to implement
    that.

    (Yes, I have had to do that. Although I think I cheated and used
    ISO-8859-1 instead. It was a lot easier and I didn't really care about
    precise handling, so long as MOST things were readable.)

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rob Cliffe@21:1/5 to Peter J. Holzer on Tue May 23 23:06:52 2023
    On 23/05/2023 22:03, Peter J. Holzer wrote:
    On 2023-05-21 20:30:45 +0100, Rob Cliffe via Python-list wrote:
    On 20/05/2023 18:54, Alex Jando wrote:
    So what I'm suggesting is something like this:

    ------------------------------------------------------------
    hash = hashlib.sha256(b'word')
    hash.=hexdigest()
    ------------------------------------------------------------
    num = Number.One
    num.=value
    ------------------------------------------------------------
    It seems to me that this would encourage bad style.  When you write
        num = num.value
    you are using num with two different meanings (an object and an
    attribute of it).
    I think that's ok if it's the same thing at a high level.

    I sometimes have a chain of transformations (e.g. first decode it, then
    strip extra spaces, then normalize spelling, then look it up in a
    database and replace it with the record, ...). Technically, of course
    all these intermediate objects are different, and I could make that
    explicit by using different variable names:

    user_param = request.GET["user"]
    user_decoded = str(user_param, encoding="utf-8")
    user_stripped = user_decoded.strip()
    user_normalized = user_stripped.lower()
    user_object = orm.user.get(name=user_normalized)

    But I find it easier to read if I just reuse the same variable name:

    user = request.GET["user"]
    user = str(user, encoding="utf-8")
    user = user.strip()
    user = user.lower()
    user = orm.user.get(name=user)

    Each instance only has a livetime of a single line (or maybe two or
    three lines if I have to combine variables), so there's little risk of confusion, and reusing the variable name makes it very clear that all
    those intermediate results are gone and won't be used again.

    hp



    Quite so.  I did imply in my full answer that this kind of thing can be appropriate in the right context.  I'm sure I've done it myself.
    Your code is a beautiful example of when such "level-crossing" IS
    appropriate; creating a plethora of variables with a short useful life
    would be a distraction which HINDERS readability ("Are any of these
    variables used later on?").
    (Not to mention the effort of thinking up suitable variable names, and
    the effort of someone reading the code to assimilate them.)
    But IMO your code would not really benefit from writing
            user .= strip()
            user .= lower()
    and allowing it would have the disadvantage (apart from all the known
    costs of adding a new feature to Python) of encouraging bad style in the
    cases where it IS bad style.
    Best wishes
    Rob Cliffe

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter J. Holzer@21:1/5 to Chris Angelico on Wed May 24 20:50:35 2023
    On 2023-05-24 08:51:19 +1000, Chris Angelico wrote:
    On Wed, 24 May 2023 at 08:48, Peter J. Holzer <hjp-python@hjp.at> wrote:
    Yes, that probably wasn't the best example. I sort of deliberately
    avoided method chaining here to make my point that you don't have to
    invent a new variable name for every intermediate result, but of course that backfired because in this case you don't need a variable name at
    all. I should have used regular function calls ...


    In the context of a .= operator, though, that is *in itself* an
    interesting data point: in order to find an example wherein the .=
    operator would be plausible, you had to make the .= operator
    unnecessary.

    Another communication failure on my part, I'm afraid: I was going off on
    a tangent about variable naming and didn't intend to show anything about
    the usefulness (or lack thereof) of a .= operator.

    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+KF0FAmRuXHYACgkQ8g5IURL+ KF3Fhw//UfEVOohoQVpVEhZjJ5WtlXpxLEGBm9mFjkaYhb5dFJ4J5hpeOv7h4Qqc DdDoc6k6A/MJrDKcYKMdbXNbJwD1DwqV9pnT6zQZvtk8C2Csu6IAv5o2nl1nsrBl Yh9dSyqyvWuOCh1WW4WRHOBhBWYF+GQLNDpKWz1sKpEZEVccMQCZz2XeVeMMq6YG MqvfFcuNd/4NKr2kYdL83gGv0S4hA40tx42YkLZekztgypPKaQGSS2ixQ4vxk5y/ ueH5yXfX0L5r2sPMM9qfHofPcTr0tXaiEzGwU1exF3b9aVpD9/DvT4o0sI24g8My kTa08Qpge2kM6ppEszPdv5oAxLaVXWD2TXdFcEUfikg7SYm/LglfYt10JBMhlJLp BHBwy843RZkJIb1PKy0D59YZPl+dahNrAGcwji8maY5LoZ8QP0Y6IrTV1vfHRG/u yHbbGGXnqJEo3IxAi5PGgpk1ljBytoyluzY29+iPOM8sPl7h37kgDv6k2lmZzMwY tntAdQMkQP8tawPO9+6lnc8BSFRcgwvoY4miZoUQaYetL4u3J+zbw0uZCg/0AcEo hDtTt5m5fTPpMo2dA3Qk24auEKokqORKqPTHsPmXGIy33PHm1kuWBuHtmt8uUUKC 7RzzK1/bw4LCVl9OWYZbICctGQl/HqXykz9eaic