[HN Gopher] Elliptical Python Programming
___________________________________________________________________
Elliptical Python Programming
Author : sebg
Score : 131 points
Date : 2025-04-10 12:53 UTC (10 hours ago)
(HTM) web link (susam.net)
(TXT) w3m dump (susam.net)
| benob wrote:
| TIL that in python, 1--2==3
| seplox wrote:
| It's not a python thing. 1-(-2), distribute the negative.
| qsort wrote:
| In most C-like languages that would be a syntax error. E.g.
| in C and C++ as a rule you tokenize "greedily", "1--2" would
| be tokenized as "1", "unary decrement operator", "2", which
| is illegal because you're trying to decerment an rvalue.
|
| Python doesn't have "--", which allows the tokenizer to do
| something else.
| nyrikki wrote:
| In C, that is really because Unary minus (negation) has
| precedence over binary operations. +a -
| b; // equivalent to (+a) - b, NOT +(a - b) -c + d;
| // equivalent to (-c) + d, NOT -(c + d)
|
| https://en.cppreference.com/w/cpp/language/operator_arithme
| t... +-e; // equivalent to +(-e), the
| unary + is a no-op if "e" is a built-in type //
| because any possible promotion is performed during negation
| already
|
| The same doesn't apply to, !! Which is applied as iterated
| binary operations (IIRC)
|
| I am pretty sure the decriment operator came around well
| after that _quirk_ was established.
| seanhunter wrote:
| Peter van der Linden's book "Expert C Programming" (which
| is awesome btw) says that one of them (Kernighan, Richie
| or maybe Ken Thompson I forget) realised early on that
| the c compiler had the wrong operator precedence for bit
| twiddling and unary and boolean operators but "at that
| stage we had a few thousand lines of C code and thought
| it would be too disruptive to change it"
| j2kun wrote:
| Also worth noting that `1 - -2` works and produces 3 in C
| because the space breaks the operator.
| plus wrote:
| For those who are curious, `...` is a placeholder value in Python
| called Ellipsis. I don't believe it serves any real purpose other
| than being a placeholder. But it is an object and it implements
| `__eq__`, and is considered equal to itself. So `...==...`
| evaluates to `True`. When you prefix a `True` with `-`, it is
| interpreted as a prefix negation operator and implicitly converts
| the `True` to a `1`, so `-(...==...)` is equal to `-1`. Then, you
| add another prefix `-` to turn the `-1` back into `1`.
|
| `--(...==...)--(...==...)` evaluates to `2` because the first
| block evaluates to 1, as previously mentioned, and then the next
| `-` is interpreted as an infix subtraction operator. The second
| `-(...==...)` evaluates to `-1`, so you get `1 - -1` or `2`.
|
| When chaining multiple together, you can leave off the initial
| `--`, because booleans will be implicitly converted to integers
| if inserted into an arithmetic expression, e.g. `True - -1` -> `1
| - -1` -> `2`.
|
| > There should be one-- and preferably only one --obvious way to
| do it.
|
| This article is obviously completely tongue-in-cheek, but I feel
| the need to point out that this sentence is not meant to be a
| complete _inversion_ of the Perl philosophy of TIMTOWTDI. The
| word "obvious" is crucial here - there can be more than one way,
| but ideally only one of the ways is obvious.
| pletnes wrote:
| Numpy actively uses ... to make slicing multidimensional arrays
| less verbose. There are also uses in FastAPI along the lines of
| <<go with the default>>.
| abuckenheimer wrote:
| excellent explanation, to add to this since I was curious about
| the composition, '%c' is an integer presentation type that
| tells python to format numbers as their corresponding unicode
| characters[1] so
|
| '%c' * (length_of_string_to_format) % (number, number, ...,
| length_of_string_to_format_numbers_later)
|
| is the expression being evaluated here after you collapse all
| of the 1s + math formatting each number in the tuple as a
| unicode char for each '%c' escape in the string corresponding
| to its place in the tuple.
|
| [1] https://docs.python.org/3/library/string.html#format-
| specifi...
| nomel wrote:
| Expanding on this a little, I will be replacing all occurrences
| of 2 with two blobs fighting, with shields:
| >>> 0^((...==...)--++--(...==...))^0 2
| rmah wrote:
| >> There should be one-- and preferably only one --obvious way
| to do it.
|
| Except for package management, of course. There, we need lots
| and lots of ways.
| elijahbenizzy wrote:
| Ok do this but for JavaScript
| voidUpdate wrote:
| https://en.wikipedia.org/wiki/JSFuck
| mariocesar wrote:
| If you're curious, the code in ellipsis results in executing:
| print('hello, world')
| mturmon wrote:
| Thank you!
|
| I noticed some ** and * in the thing sent to eval(), which
| (given that the building blocks are small integers) seemed
| related to prime factorizations.
|
| The initial %c is duplicated 21 times (3*7, if I read
| correctly), and then string-interpolated (%c%c%c...) against a
| long tuple of integers. These integers themselves are composed
| of products of factors combined using * and **.
|
| There is also one tuple "multiplication" embedded within that
| long tuple of integers -- (a,b)*2 = (a,b,a,b). That is for the
| 'l' 'l' in "hello".
|
| It's all very clever and amusingly mathy, with a winking
| allusion to the construction of natural numbers using sets. It
| made me Godel.
| callamdelaney wrote:
| I think we're really starting to over crowd pythons syntax and
| I'm not a fan.
| noddleah wrote:
| you're telling me you never program in python elliptically??
| acbart wrote:
| Pretty sure this would have been possible in Python 2.6. The
| Ellipsis object has been around for a very long time.
| MadVikingGod wrote:
| This behavior can be replicated with any class that has two
| special methods: __neg__ that returns -1 and __sub__ that accepts
| ints and returns 1-other.
|
| For example if you make this class: class _:
| def __neg__(self): return -1 def
| __sub__(self, other): return 1-other
|
| You get similar behavior: >>> --_() 1
| >>> _()--_() 2
|
| Fun python for everyone.
| maxloh wrote:
| You can do this on JavaScript too. alert(1)
| // equals to: [][(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[
| ])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+
| !+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!
| +[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+(
| [][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[
| +[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]
| +[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!
| +[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+!+[]]+(!!
| []+[])[+[]]]+[])[+!+[]+[+!+[]]]+[+!+[]]+([]+[]+[][(![]+[])[+!+[]]
| +(!![]+[])[+[]]])[+!+[]+[!+[]+!+[]]])()
|
| https://jsfuck.com/
___________________________________________________________________
(page generated 2025-04-10 23:00 UTC)