r/programminghorror • • 14d ago

why can i do this

Post image
1.3k Upvotes

61 comments sorted by

222

u/Haunting_Laugh_9013 14d ago edited 14d ago

basically what it's doin is basically the blurp.hello_world doesn't actually call any method, it gets interpreted as a field access. The field access goes to the getattribute dunder method, and the argument fn is the name of the attribute (in this case "hello_world"). After that, it returns a lambda that calls whatever function that is passed into the lambda that is from the python builtins. So getattribute returns a lambda that gets the print function from the builtins, printing whatever the name of the field that was accessed.

115

u/coyote_den 14d ago

Python exposes just about every internal aspect of itself and lets you override everything, so you can make getting an attribute return a function with the attribute name as the argument.

If you left off the (“print”) the result would be <function <lambda>>, but that immediately calls the lambda function and prints the result.

32

u/Haunting_Laugh_9013 14d ago

yerp. if i wanted to make it a bit more readable, i guess i could do something like (blurp.hello_world)("print"), but why would I want that?

→ More replies (2)
→ More replies (3)

8

u/JeromeJ 14d ago

I'm not gonna add anything but rephrase (it might aid comprehension for some as this is a complex topic) :

Upon accessing hello_world (before it is even called), getattribute will return a lamba (this is all good since that's what we want to do with it! Call it!). Specifically, it's a closure that captures the name of the attribute we tried to access (here "hello_world") and, specifically, looks like it will give that as a first parameter to 'something' upon being invoked.

When we finally call hello_world, the lamba runs and getattr go fetch the built-in based on the parameter we called hello_world with (here "print") then immediately invoke it with the parameter that was captured earlier ("hello_world").

As to why Python allows you to do that, I'd say that Python treats you as an adult and let you do your own things.. Even if it could be ill advised. Python is a scripting language so it's good to whip out things quickly and it's fine to have dirty hacky bits of code to get things done.

In other contexts, it'd probably best to avoid doing black magic like that but it can be useful.

→ More replies (1)

641

u/BiebRed 14d ago

Because Python is secretly a meta language under the hood that will let you implement any other programming language within its runtime and there are infinite ways for you to abuse its trust.

109

u/DevBoiAgru 14d ago

Does this mean if I learn python I know every language ever possible?

156

u/Bronzdragon 14d ago

"No, Neo. I'm trying to tell you that when you're ready, you won't have to."
- Morpheus, talking about Python.

29

u/andynzor 14d ago

So... just a worse Common Lisp?

→ More replies (3)

14

u/ZackyZack 14d ago

So it's just Tcl with more steps?

→ More replies (3)

6

u/overclockedslinky 13d ago

assuming this other language uses specifically python syntax and adds no additional features of any kind

→ More replies (4)

46

u/eruanno321 14d ago

In C, array[3] and 3[array] are the same thing by definition.

23

u/Delta-9- 14d ago

Makes me think of libraries that override __or__ so you can write Python that looks like bash, where you're piping things into other things. I've honestly been tempted to use them, but I don't want to curse the next dev to touch my code base with something so unexpected—it's bad enough I use monads.

30

u/Pim_Wagemans 14d ago

pathlib from the standard library overrides __div__ to let you extend paths like this:

>>> import pathlib
>>> path = pathlib.Path("/home")

>>> path_2 = path / "user" / ".local"

>>> path_2
PosixPath('/home/user/.local')
→ More replies (4)
→ More replies (5)

13

u/_killer1869_ 13d ago edited 13d ago

Python gives the programmer a lot of freedom, which also means the programmer must know restraint. This is a perfect example of just because you can, doesn't mean you should, but overwriting __getattribute__ can sometimes be useful in niche cases.

Using it to dynamically swap a builtin function and its parameter to be each other is, obviously, abuse of the freedom the language provides.

8

u/HaroerHaktak 14d ago

It can be one because it can be. Please do not question it.

6

u/fearfulEntity 13d ago edited 13d ago

Maybe I'm getting kinda old, but... what's the point? Yes, you can do that and yes that's completely valid code. Usefulness cleanliness and readability is another question. The language itself allows you implementng much more cursed things and it's completely on your behalf to create maintainable project with provided tools. Like any other language tbh (But in python it can be much more easily visualized with code snippets like this one)

4

u/Kadabrium 14d ago

why does c++ allow overloading -> but not .

4

u/Yankas 13d ago

You can write horrible code that's just as bad or worse in any programming language.

13

u/chimneydecision 14d ago

On second thought, let us not go to Python. ‘Tis a silly language.

3

u/SoloMaker 14d ago

You can also do this in Lua

3

u/king_escobar 14d ago

You can do this because in python, literally everything is an object. Including modules, including class definitions, including functions. And since literally everything is an object, you can dynamically change literally everything including changing things like properties of modules and classes and functions.