218
u/Haunting_Laugh_9013 4d ago edited 4d 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.
113
u/coyote_den 4d 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.
34
u/Haunting_Laugh_9013 4d 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?33
u/Haunting_Laugh_9013 4d ago
"There should be one-- and preferably only one --obvious way to do it." - The Zen of Python ```python def prent(streng: str):
blurp = Blorp() getattr(blurp, streng)("print")prent("hello world!") print("hello world!") ```
Whatcha think of that Guido? (̿▀̿‿ ̿▀̿ ̿)
4
4
u/Limp_Illustrator7614 4d ago edited 3d ago
Python exposes just about every internal aspect of itself and lets you override everything
i mean, not really. that description fits ruby more. you cant override stuff like int and list cuz they're implemented in c for performance i think?
EDIT: today i learned
18
u/person4268 4d ago edited 3d ago
Not if you reach into the C with ctypes, then you can rearrange for instance, the values of the cached int instances of common numbers:
```python Python 3.14.7 (main, Aug 10 2026, 07:46:56) [GCC 16.1.1 20260728] on linux
Type "help", "copyright", "credits" or "license" for more information.
import ctypes ... def deref(addr, typ): ... return ctypes.cast(addr, ctypes.POINTER(typ)) ... deref(id(29), ctypes.c_int)[6] = 100
29 100 28 + 1 100
```10
7
u/JeromeJ 4d ago
I'm not gonna add anything but rephrase (it might aid comprehension for some as this is a complex topic) :
Upon accessing helloworld (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.
1
43
21
u/Delta-9- 4d 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.
26
u/Pim_Wagemans 4d 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')6
1
u/Yadobler 2d ago
This is so c++. It always bugged me to do that but fstrings would be quite messy too and putting them in an array and merging is too excessive. Plus this way also allows pathlib to escape characters that one might forget or not know how to do when trying to handle path strings with variables
0
1
u/itzNukeey 3d ago
How are you using monads in python?
2
u/Delta-9- 3d ago
Mostly for chaining together functions where one or more of them may raise or return a None, but the equivalent if-else blocks would be tedious to write or hard to read for their sheer number. I've tried using them for dependency injection, but the resulting code seemed so foreign to Python I've decided not to use it.
1
0
u/Bob_Dieter 4d ago
How do you use monad in python? To use monads in an ergonomic way, you need to be able to create many small-ish continuation functions, and pythons syntax for that is horseshit.
1
u/Delta-9- 4d ago
Lambdas and partials work just fine, but a lot of the time I just pass a regular function in.
The
returnslibrary also did something clever with list comprehension syntax to emulate do-notation in Haskell. I don't use it much, but it makes long chains look much simpler.
11
u/_killer1869_ 4d ago edited 3d 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.
7
8
6
u/fearfulEntity 3d ago edited 3d 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)
5
5
14
3
3
u/king_escobar 4d 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.
2
2
3
u/RoyalStraightjacket 3d ago edited 3d ago
Can someone explain how blurp = blorp? I'm new to programming.
Edit: Who the *bleep* downvoted me?
2
u/BenK1222 3d ago
In Python,
=is the assignment operator. In the line, OP is assigning the variableblurpto a new instance of theBlorpclass.
2
u/SimpleDisastrous4483 4d ago
I love it. Python is so hilariously permissive, and this is a very fun way to do dumb things with it
1
1
u/Cheap-Cut7910 4d ago
Python is basically chaos wrapped in syntax.
1
u/MurkyWar2756 echo "Sub Mod" && :(){ :|:& };: 1d ago
This is the first, or maybe second, time I see an exit fullscreen icon followed by "Potential Spam" next to a comment.
0
621
u/BiebRed 4d 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.