• huppenzuppen (unregistered)

    This form of ternaries is not unique to Python, VHDL has a similar construct

  • LZ79LRU (unregistered)

    The language was named after the Monty Python Flying Circus who specialize in satirical WTF comedy. Is it really that surprising when the code produced in it resembles the same?

  • Foo AKA Fooo (unregistered)

    "Each rule is identified by a number, which does a wonderful job making the code more cryptic. Are there at least 241 rules, or is the numbering sparse? What does rule 241 represent? Absolutely no idea."

    Every good Ferengi knows the rules and numbers by heart (https://memory-beta.fandom.com/wiki/Ferengi_Rules_of_Acquisition). Hmm, number 241 is missing on that page, but now we see it must be about illusion of choice in marketing or such.

  • some guy (unregistered)

    So python thinks that the true condition is the more likely one? I prefer clarity of the condition over having to guess which outcome is more likely such that I can formulate the condition accordingly.

    It could also be that the getcall has a side effect, but that leads to more WTFery.

    Final nitpick: why is this not "Representative Line"?

  • NoLand (unregistered)

    This has already been a feature in Algol. (Compare the Revised Report on the Algorithmic Language Algol 60, 4.5 Conditional statements.)

  • NoLand (unregistered)

    Correction: it's actually defined in "3.3. Arithmetic expressions", which may include a Boolean expression.

    And, if you thought Python was bad, have a look at this Algol beauty provided in the Revised Report ("3.4. Boolean expressions"):

    if if if a then b else c then d else f then g else h < k
    

    (Any if-else pair evaluates to a value, and you can nest them, as deep as you want.)

  • (nodebb)

    There's one advantage to the current code: letting get raise (throw) an error (exception). If "dead code removal" were applied here to collapse the ternary to False, the error would never get raised. Of course, no programmer should be expecting that error that would prevent dead code removal, but this website never fails to prove us wrong.

  • (nodebb)

    Pythonic way is synonymous with "write semi-crazy crap on purpose".

    No thanks.

  • (nodebb) in reply to NoLand

    Fun fact: there exists a language with "no" reserved words: IBM's PL/I from the mid-60s. The idea was that new keywords could be added to the language in the future without invalidating old programs. This has the "neat" benefit that this monstrosity is valid syntax (correct me if the ELIF/ENDIF keywords are wrong):

    IF IF = THEN THEN THEN = ELIF ELIF ELIF = THEN THEN THEN = ELSE ELSE ELSE = ENDIF ENDIF
    

    That should be read as (in C# where the "at sign" allows using keywords as variable names):

    int @if, then, elif, @else, endif;
    ...
    if (@if == then)
        then = elif;
    else if (elif == then)
        then = @else;
    else
        @else = endif;
    
  • (nodebb)

    *fumes in one-way-to-do-it*

    Python's ternary expression is one of the weird choices of python that keep me annoyed over what is otherwise my least disliked language for actually getting things done.

    Throughout python, you usually have a pattern of “evaluate in order written”. You have

    if A:
        B1
    else:
        B2
    

    or with loops

    for item in A:
        B(item)
    

    i.e. A is evaluated before B. But when you go to expressions, it is suddenly reversed.

    out = B1 if A else B2
    out = [B(item) for item in A]
    

    This reversal becomes even more obnoxious, when you want to do more complex things.

    >>> for i in "AB": 
    ...     for j in "12": 
    ...         print(i+j, end=" ")
    A1 A2 B1 B2
    

    so far clear, but what if you use the same order in a generator or list expression?

    >>> print(" ".join(i+j for i in "AB" for j in "12"))
    A1 A2 B1 B2
    

    Okay, nice so far. And what, if it is a nested list?

    >>> print([[ i+j for i in "AB" ] for j in "12" ])
    [['A1', 'B1'], ['A2', 'B2']]
    

    Due to this, the "flat" generator expression is always trial-and-error for me.

    Additionally, it undermines intellisense features of IDEs; In loop expressions you write the item before the source, so by the time you have written

    out = [i
    

    the IDE cannot yet decide what type i will be.

    I would much have preferred if Python had opted for expressions of the form

    out = if A then B1 else B2
    out = for item in A collect B(item)
    

    but history is strange.

    I've recently also learned that (mostly for historical reasons, see PEP 285 – Adding a bool type (Python 2.3)) Python draws a surprisingly fuzzy line between booleans and integers.

  • NoLand (unregistered) in reply to colejohnson66

    I guess, this is one of the Wittgensteinian influences on PL/I. (The Vienna group did engage in some Wittgenstein studies, and this is pretty much a language game, AKA Sprachspiel, where meaning is derived from use.)

  • (nodebb) in reply to colejohnson66

    Fun fact: there exists a language with "no" reserved words:

    There is another one. The following is valid Fortran:

    program program
        integer :: if = 1
        integer :: else = 2
        if(if == 1) then
           print *, if
        else
           print *, else
        end if
    end program program
    

    In Fortran, keywords are not keywords, unless they are in places, where they are expected. Otherwise they just ‘degrade’ to an identifier. Curiously though, this is not entirely consistent; The following would be incorrect syntax:

    program program
        integer if = 1
        integer else = 2
        if(if == 1) then
           print *, if
        else
           print *, else
        end if
    
    end program program
    

    with error messages from as

    ! Intel
    a.f90(4): error #5082: Syntax error, found IDENTIFIER 'IF' when expecting one of: ( : % [ . = =>
            integer if = 1
    ----------------^
    ! Gfortran
    a.f90:4:18:
    
             integer if = 1
                      1
    Error: Syntax error in data declaration at (1)
    

    Addendum 2023-05-04 07:51: ~~from as~~ such as

  • (nodebb) in reply to R3D3

    Oh, don't forget about Smalltalk. Theoretically it doesn't have any reserved words; practically the compiler optimizes "nil" and "==", but the rest can be redefined. Even true and false are just global constants.

    So you can write: true become: false

    ... and your whole system will stop working immediately.

  • (nodebb) in reply to Melissa U

    Lisp is the same way. 1 is not really the integer 1, it's a function that returns the integer 1. And Lisp lets you redefine functions.

  • (nodebb)
    for example, you don't use switch statements in Python, you put callable functions in a dict instead.

    I've been writing Python for quite a while now, and I've never seen anyone do this.

  • Smalltalkers do: [:it | All with: Class, (And love: it)] (unregistered) in reply to Melissa U
    Comment held for moderation.
  • Gubbo (unregistered) in reply to Dragnslcr
    Comment held for moderation.
  • LZ79LRU (unregistered) in reply to Dragnslcr

    I have. And a lot of other things. This includes an unfortunate developer who got squished by a giant foot.

  • Barry Margolin (github) in reply to Dragnslcr

    1 is not really the integer 1, it's a function that returns the integer 1.

    Not in any Lisp dialect I've ever used (MacLisp, Common Lisp, Scheme, Emacs Lisp to name a few).

    Functions are named by symbols. While it's possible to create a symbol whose name is a number, you have to use escaping to refer to it, by writing either |1| or \1. If you just write 1 by itself, it's parsed as an integer and you can't use it as a function name.

    (defun 1 (x) (print x))
    

    is not valid code.

  • Barry Margolin (github) in reply to colejohnson66

    There's one advantage to the current code: letting get raise (throw) an error (exception).

    get() doesn't raise an exception when the key isn't found, it returns a default value (the second argument, which defaults to None). The exception is raised when you use subscript notation, rules[241].

    The author of the code made a classic beginner WTF, writing something != X or Y when they mean something not in (X ,Y)

  • (nodebb) in reply to LZ79LRU

    Well, sure, stupid programmers do stupid things. That still doesn't make it the thing you're supposed to do.

    I definitely agree that the order in Python's ternary is weird, though.

  • efahl (unregistered)
    Comment held for moderation.
  • Davidmh (unregistered)
    Comment held for moderation.
  • WTFGuy (unregistered)

    Ref

    So python thinks that the true condition is the more likely one? I prefer clarity of the condition over having to guess which outcome is more likely such that I can formulate the condition accordingly.

    What does likelihood of being true or false have to do with the structure of the statement? Construct your condition for clarity and put the true and false results in the syntactically required locations. Anything else is paying foolish attention to low-level concerns from within a high level language. Don't do that.

  • matt (unregistered)
    Comment held for moderation.
  • some guy (unregistered) in reply to WTFGuy
    Comment held for moderation.
  • (nodebb)
    Comment held for moderation.
  • xtal256 (unregistered) in reply to Melissa U

    Yes and it uses the sane ordering of condition and values, so that the expression would be written:

    welcome_mt := (rules get: 241) ~= 'yes' ifTrue: [ false ] ifFalse: [ false ]

    and it would be immediately obvious how stupid and redundant it is.

    Smalltalk is the only language I've seen that doesn't do things in an ass-backwards way, and yet no one uses it.

  • löchlein deluxe (unregistered) in reply to Dragnslcr
    Comment held for moderation.
  • Nick (unregistered)

    The real WTF here is the assumption that just because the rule ID happens to contain digit, all rules IDs are numbers.

    Clearly, this is a shopping cart system, and this rule is the “2 items for the price of 1” rule, aka “2-4-1”, or just “241” to avoid looking like maths.

    Other rules in the system probably include “BOGOF”, “342” and “1/2OFF”

  • LZ79LRU (unregistered) in reply to Dragnslcr

    Python is way more problematic than most languages though. I mean, look at its main "feature", significant whitespace. It is literally a violation of the principal of separation of concerns built into the language.

  • (nodebb)

    Python's ternary is not the real WTF.

    The Real WTF is that Python's ternary is a NEW thing since version 3. Before, the author had flatly refused to add one, which led folks to write this Pythonic monstrous workaround:

    a and b or c

    Which reads as (a ? b : c). And a lot of subtle "hilarity ensues" edge cases. Ironically this thing has the right order.

  • (nodebb) in reply to Mr. TA

    This is a very narrow view of python. Have you actually done any working in the language of python? Here is a non-pythonic way to write a loop.

    for i in range(10): print(i)

    Here is the same loop, but in a pythonic way.

    print([i for i in range(10)])

    Clearly we are all opinionated python programmers.

  • (nodebb) in reply to LZ79LRU

    Sorry, but the spacing is making it easier to reading.

  • Nikhil Kashyap (unregistered)
    Comment held for moderation.
  • seebs (unregistered)
    Comment held for moderation.
  • LZ79LRU (unregistered) in reply to Nagesh
    Comment held for moderation.
  • (nodebb) in reply to Nagesh

    Here is a non-pythonic way to write a loop.

    for i in range(10): print(i)
    

    Here is the same loop, but in a pythonic way.

    print([i for i in range(10)])
    

    Clearly we are all opinionated python programmers.

    Uhm... what? Those are two different loops with different outputs, and both look perfectly pythonic to me.

    Sorry, but the spacing is making it easier to reading.

    Code formatters fulfill the same job though. Just because there are beginners and (for whatever reason) lecturers that do bad code formatting doesn't make it a good idea to make it compulsory.

    It's also not like it is a complete solution. Python prescribes indenting for block syntax, which essentially only solves the

    if(COND) {
        THEN
    }
    

    vs

    if(COND)
    {
        THEN
    }
    

    choice. I haven't really seen anything else in the wild, except as a joke or outlier. But just as you could quarrel about {\n vs \n{, you can quarrel about whether to put an empty line at the end of a block (to make it more visually distinct) or not, and when.

    It also doesn't do anything to help with formatting of multi-line expressions (e.g. nested function calls or (nested) list/dict literals, or just long expressions/statements.

    It also sabotages some useful syntax. For instance, an equivalent of Javascript's

    const selected_items = getAllItems().filter(e => /* ...*/).map(e => /* ...*/)
    

    is more limited, because it doesn't allow for fully functional code blocks, but only for lambda expressions, where neither raising exceptions nor logging statements work well. Instead you have to do something more awkward like

    def some_function_1(e):
        ...
    def some_function_2(e):
        ...
    selected_items = get_all_items().filter(some_function_1).map(some_function_2)
    

    That assumes having some sort of "piping" library involved though. With pure python it would be <!-- to be continued -->

  • (nodebb)
    selected_items = map(
        some_function_2, 
        filter(
            some_function_1, 
            get_all_items(),
        )
    )
    

    which I consider significantly less clear, even after years of using Python. Note that my JavaScript expertise is rather basic, I've never used it nearly on the scale I've used Python.

    Additionally, this dichotomy of lambda vs makes refactoring often more painful then necessary, when you have to switch from a lambda expression to a named (local?) function, which often requires rewriting the structure of the code, rather than just the implementation details. Also makes for less clear diffs.

    Speaking of diffs, another point where significant whitespace can be a pain :/

  • LZ79LRU (unregistered)
    Comment held for moderation.
  • Muhammad Numan (unregistered)
    Comment held for moderation.
  • CWiz (unregistered)
    Comment held for moderation.
  • Alessandro (unregistered) in reply to colejohnson66
    Comment held for moderation.

Leave a comment on “Python's Tern”

Log In or post as a guest

Replying to comment #:

« Return to Article