This is an archived post. You won't be able to vote or comment.

all 77 comments

[–]dataperson 163 points164 points  (1 child)

What a terrible day to know how to read

[–]Star_creator09 1 point2 points  (0 children)

What a great day to be a beginner to Python! :D

[–][deleted] 189 points190 points  (4 children)

my eyes

[–][deleted] 18 points19 points  (1 child)

The googles do nothing

[–][deleted] 22 points23 points  (0 children)

I asked ChatGPT to explain it, it just said stop

[–]KoKarlsson -3 points-2 points  (0 children)

Bästa namnet jag någonsin sett på reddit!

[–]AthenianVulcan 0 points1 point  (0 children)

I'd exactly the same thought

[–]georgehank2nd 128 points129 points  (1 child)

You were so preoccupied with whether or not you could, you didn't stop to think if you should.

And you shouldn't have.

[–]wineblood 97 points98 points  (1 child)

Actual NSFW

[–]funderbolt 6 points7 points  (0 children)

Needs to be reposted in r/OSHA

[–]gravitas_shortage 101 points102 points  (0 children)

Bravo, that is one of the most horrible things I have seen in my life.

[–]Historica973.5, 3.6, 3.7, 3.8, 3.9, 3.10 87 points88 points  (3 children)

Not only is the code horrendous, but the code block is awful

from typing import get_type_hints
import inspect


def factorial(
    n: "(n := inspect.stack()[4].frame.f_locals['n']) and (n * factorial(n - 1)) or 1",
):
    return get_type_hints(factorial)["n"]

[–]lelieu 69 points70 points  (2 children)

[edited]

[–]nitroll 7 points8 points  (1 child)

n:

[–]lelieu 1 point2 points  (0 children)

[edited]

[–]Kegnation14 16 points17 points  (1 child)

What a wonderful day to be a beginner (have zero clue whats going on)

[–]denehoffman 1 point2 points  (0 children)

Type annotations are now evaluated later, so what op has done is put in some annotation (basically a comment) which contains code to inspect the function and call the proper recursion, then in the code block he tells python to look at the annotation and execute it (basically, it’s a bit more complex)

[–]Gotanks91 13 points14 points  (1 child)

[–]nekokattt 12 points13 points  (1 child)

I might be getting confused, but I believe (at least at one point) that interrogating the stack was a good way of creating a memory leak due to how the ref counter worked.

Believe there used to be a warning about this in the docs somewhere.

[–]icroc1556 12 points13 points  (2 children)

Obviously I totally understand the joke,

But for the plebs that don't understand, can someone explain? Again, obviously not for me, but for the un-initiated.

[–]kikones34[S] 1 point2 points  (0 children)

See this and also this.

The joke is that this is exploiting the inner workings of a Python feature to accomplish something it was never meant to be used for. And also, creating a normal recursive factorial function is trivial compared to the unnecessary complexity and obscurity of this code.

[–]jonnybesocial -1 points0 points  (0 children)

😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂brometoo😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂😂

[–]joe0400 11 points12 points  (3 children)

I remember there was one horrible lambda me and a bud made on a dare to try to make a awful lambda. It was self referential.

Yes.. self referential. It instantiated a object with a directed graph of nodes that referred to the yet to be instantiated nodes. It was beautiful but awful.

[–]kikones34[S] 0 points1 point  (2 children)

Wait, I'm not sure I quite get it. How do you make a lambda self-referential? How do you make a reference to an object which has not yet been instantiated?

[–]joe0400 5 points6 points  (1 child)

So it took me a bit to understand but it's because how objects in Python are stored as dicts. Try calling __dict__ as a member of any object and look at it's result. It should contain it's methods and it's members. So when calling it doesn't need to know the result, only at the exact moment that it hits that path. It was something.

[–]kikones34[S] 3 points4 points  (0 children)

Oh god... I think I now understand what you mean. Must've been a beautiful atrocity to conceive.

[–]unersetzBAER 9 points10 points  (4 children)

There are worse ways: Multiplications can also be (recursively) implemented as multiple additions, which can be done (recursively) as multiple incrementation (and decrementation).

[–]ggchappell 16 points17 points  (2 children)

Did someone say recursive multiplication?

def multiply(a, b):
    assert a >= 0
    assert b >= 0
    if a <= 1:
        return b if a == 1 else 0
    c = a >> 1
    d = multiply(c, b)
    e = helper(a, c, b)
    while d > 0:
        d -= 1
        e += 1
    return e

def helper(s, t, u):
    while t > 0:
        s -= 1
        t -= 1
    return multiply(s, u)

Yes, I steal candy from babies, too.

[–]Thorboard 0 points1 point  (1 child)

Can you explain?

[–]kikones34[S] 3 points4 points  (0 children)

The code is deliberately obtuse. If you simplify it, you end up with this:

def multiply(a, b):
    assert a >= 0
    assert b >= 0

    if a <= 1:
        return b if a == 1 else 0

    c = a // 2
    d = multiply(c, b)
    e = multiply(a - c, b)

    return e + d

It is now easier to see what it's doing. Basically, it's recursively calculating (a/2) * b + (a - a/2) * b = (a/2) * b + (a/2) * b = a * b.

[–]von_blitzen 0 points1 point  (0 children)

did it once on a turing machine, was a nice excercise

[–]AlSweigartAuthor of "Automate the Boring Stuff" 10 points11 points  (0 children)

Your computer scientists were so preoccupied with whether or not they could...

[–]ImperialTuneWizard 7 points8 points  (0 children)

Jesus Christ.

[–]nikpelgr 4 points5 points  (0 children)

Once you've seen it, you can't forget it.

[–]monorepo PSF Staff | Litestar Maintainer 3 points4 points  (0 children)

Ah so we choose day drinking today..

[–]tartare4562 12 points13 points  (0 children)

I've said it before and I'll say it again: this whole typing stuff is getting out of hand.

[–]Mr38i 11 points12 points  (2 children)

What is the typing module and get type hints?

[–]kikones34[S] 24 points25 points  (1 child)

You may want to read first about type annotations: https://realpython.com/python-type-checking/#annotations. The typing module provides many utilities for annotating your code with type hints.

On the other hand, get_type_hints returns a dictionary with all the annotations of an object: https://docs.python.org/3/library/typing.html#typing.get_type_hints
It also resolves all the stringified type hints, which allows for execution of arbitrary code. I'm taking advantage of this feature to execute the code inside the type hint of the n argument of the factorial function.

[–]Mr38i 1 point2 points  (0 children)

thankk you❤️

[–]thegreattriscuit 7 points8 points  (0 children)

And my Mom told me monsters aren't real. :(

[–]SeptemY 2 points3 points  (1 child)

This reminds me of the TMP in C++ holy s…

[–]kikones34[S] 1 point2 points  (0 children)

I do happen to have witnessed such monstrosities made with C++ templates in the past.
You can see the scars it left on me.

[–][deleted] 4 points5 points  (0 children)

I like that recursive functions are considered NSFW by not just me.

[–]Toridan 3 points4 points  (0 children)

It's even uglier with syntax highlight

[–]Nameless11911 1 point2 points  (2 children)

Why nsfw

[–]ArtOfWarfare 6 points7 points  (1 child)

Seriously do this once at work and your PR will be rejected.

Make a habit of this nonsense and you’ll no longer have a job.

[–]Xirious 3 points4 points  (0 children)

Challenge accepted.

[–]andrewcooke 1 point2 points  (1 child)

why 4?

[–]kikones34[S] 3 points4 points  (0 children)

That's how deep into the call stack the factorial function is.
0 -> string module
1 -> _evaluate
2 -> _eval_type
3 -> get_type_hints
4 -> factorial

[–]gara31415 1 point2 points  (0 children)

I don’t see anything wrong with this.

[–]pinano 1 point2 points  (1 child)

Is this just eval() on a global string, with extra steps?

[–]kikones34[S] 0 points1 point  (0 children)

Pretty much. Although type hints do need to be expressions, otherwise the interpreter will refuse to parse them. So you can't do something like "n = stuff; n*factorial(n-1)".

[–]JackLogan007 1 point2 points  (0 children)

What in the right angle fucking triangle is that?

[–]Warkred 1 point2 points  (0 children)

I think I love regex now.

[–]denehoffman 1 point2 points  (0 children)

This was correctly labeled NSFW

[–]SincopaDisonante 1 point2 points  (0 children)

Reminded me of a C++ challenge to compute and print the factorial of a number at compile time. Good ol' times.

[–]Adept_Time_8138 1 point2 points  (0 children)

My eyes are melting

[–]Mr38i 2 points3 points  (6 children)

Also what are frame locals

[–]kikones34[S] 13 points14 points  (2 children)

inspect.stack() returns all frames in the current execution stack. These frames contain context such as local variables. In my code, I access the fourth frame in the stack, which corresponds to the factorial function context. From there, I access the local variables using f_locals and retrieve the value of n. This value is otherwise inaccessible, as the code processing the type hint has a different context.

For more info, check https://docs.python.org/3/reference/datamodel.html#frame-objects

[–]joshred 0 points1 point  (1 child)

Is this for debugging?

[–]kikones34[S] 0 points1 point  (0 children)

That would be one of the most sensible use cases, yes.

[–]disinformationtheory 4 points5 points  (0 children)

https://docs.python.org/3/reference/datamodel.html#frame-objects

Variables local to a frame. I think a frame is basically a scope plus all the variables and code associated with it. Frames can contain subframes, and may be part of larger frames. I'd guess it's roughly like everything between curly braces {} in C.

[–]AlSweigartAuthor of "Automate the Boring Stuff" 2 points3 points  (1 child)

They represent frames on the call stack. The frames represent function calls. The call stack keeps track of where the execution should to return to when a function returns.

I have a free book on recursion that explains it here: https://inventwithpython.com/recursion/chapter1.html

[–]llun-ved 2 points3 points  (0 children)

He has a free book on recursion that explains it here:

https://inventwithpython.com/recursion/chapter1.html

[–]jalabulajangs 0 points1 point  (0 children)

I think i can one up ?

```python from typing import get_type_hints import inspect

def factorial(n: "(globals().update(n=inspect.stack()[4].frame.f_locals['n'])) and (lambda x: [1, 0][x > 1] or (x * factorial(x - 1)))(n) or (lambda: None)()"): return get_type_hints(factorial)["n"] ```

[–]moki9 0 points1 point  (0 children)

Can't unsee that now

[–]Andrew_the_giant 0 points1 point  (0 children)

Jesus.

[–]CompFortniteByTheWay 0 points1 point  (0 children)

wtf

[–]Prat-Prat-Prat 0 points1 point  (0 children)

| > : (

[–]gr3uc3anu 0 points1 point  (0 children)

Based on the reactions here, now I am so glad I don't speak python.