#🔒 The point of __build_class__?
29 messages · Page 1 of 1 (latest)
@rose umbra
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
The actual implementation depends on the python interpreter that's being used, but this generally handles actually building the class and returning it for the current namespace
For this stuff you can typically find original discussion on design etc, like this from the python creator https://mail.python.org/pipermail/python-3000/2007-March/006338.html which is fun
!e py import dis dis.dis(''' class Example: def do_thing(self): print("hello") ''')
@steel yew :white_check_mark: Your 3.12 eval job has completed with return code 0.
001 | 0 0 RESUME 0
002 |
003 | 2 2 PUSH_NULL
004 | 4 LOAD_BUILD_CLASS
005 | 6 LOAD_CONST 0 (<code object Example at 0x7f96dbc09a70, file "<dis>", line 2>)
006 | 8 MAKE_FUNCTION 0
007 | 10 LOAD_CONST 1 ('Example')
008 | 12 CALL 2
009 | 20 STORE_NAME 0 (Example)
010 | 22 RETURN_CONST 2 (None)
011 |
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/QTRABHSRYD2A5ZCW46WWLYNARY
oh right yeah of course it gets truncated
0 0 RESUME 0
2 2 PUSH_NULL
4 LOAD_BUILD_CLASS
6 LOAD_CONST 0 (<code object Example at 0x7f96dbc09a70, file "<dis>", line 2>)
8 MAKE_FUNCTION 0
10 LOAD_CONST 1 ('Example')
12 CALL 2
20 STORE_NAME 0 (Example)
22 RETURN_CONST 2 (None)
Disassembly of <code object Example at 0x7f96dbc09a70, file "<dis>", line 2>:
2 0 RESUME 0
2 LOAD_NAME 0 (__name__)
4 STORE_NAME 1 (__module__)
6 LOAD_CONST 0 ('Example')
8 STORE_NAME 2 (__qualname__)
3 10 LOAD_CONST 1 (<code object do_thing at 0x7f96dbc0a5d0, file "<dis>", line 3>)
12 MAKE_FUNCTION 0
14 STORE_NAME 3 (do_thing)
16 RETURN_CONST 2 (None)
Disassembly of <code object do_thing at 0x7f96dbc0a5d0, file "<dis>", line 3>:
3 0 RESUME 0
4 2 LOAD_GLOBAL 1 (NULL + print)
12 LOAD_CONST 1 ('hello')
14 CALL 1
22 POP_TOP
24 RETURN_CONST 0 (None)``` here's the full output
LOAD_BUILD_CLASS is a special instruction that just gets you the function __build_class__
so you can see that what making a class actually does is something more like this py def Example(): __module__ = __name__ __qualname__ = "Example" def do_thing(self): print("hello") Example = __build_class__(Example, "Example")
as for why it does that... well it's interpreter implementation details so it is ultimately just "they decided to do it that way", but also like, it makes sense? the block of code inside a class has to get ran inside a special namespace because of the magic thing, and making a separate code object is the easiest way to produce a new namespace
turning it into a function might not seem particularly necessary but it causes it to capture the scope around it, where a code object by itself is a constant and would not be able to access variables outside itself
and then making __build_class__ a function instead of just a BUILD_CLASS instruction... ok i have no idea what the rationale is behind that one
possibly it's so you can supply your own if for some reason you want to hook all the classes? idk
^ every language feature has a backing function.
My main interest for this is that I am making some programming games, and of course I need to sandbox the inputs. And I've been experimenting with "unlocks" like the ability to allow the player to make functions or classes. Also I know I'll have to restrict import.
Guido mentioned in that mailing list post above it’s so that it can easily reuse all the logic for *args, **kwargs etc.
take a look at runpy
Soo... I probably do not really need __build_class__ for anything?
no. It's an internal function.
Trying to sandbox inside Python code really isn’t a good idea. The language is so introspectable that it’s very easy to break out of those.
Really the best solution is to put the code in like a VM, or maybe run a web assembly build.
os.chroot(path)```
Change the root directory of the current process to *path*.
[Availability](https://docs.python.org/3/library/intro.html#availability): Unix, not Emscripten, not WASI.
Changed in version 3.6: Accepts a [path-like object](https://docs.python.org/3/glossary.html#term-path-like-object).
^do that inside os.fork()
# main.py
import os,sys
somevar = someimportantdata
pid = os.fork()
if pid:
# this is the parent process... do whatever needs to be done as the parent
else:
# we are the child process... lets do that plugin thing!
os.setgid(gid) # Important! Set GID first! See comments for details.
os.setuid(uid)
os.chroot(chrootpath)
import untrustworthyplugin
untrustworthyplugin.run(somevar)
sys.exit(0)
This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.