__build_class__ in Python >= 3.5

Viewed 308

I have troubles building a class manually in newer versions of Python.

class A:
  x = 13
  print(locals())

print(A.x)

def f():
  __module__ = '__main__'
  __qualname__ = 'B'
  x = 13
  print(locals())

B = __build_class__(f, 'B')
print(hasattr(B, 'x'))

# just for debugging
import inspect
import dis
dis.dis(inspect.currentframe().f_code)

The bytecode seems mostly the same, but B class has no attribute x at the end. Am I missing something? In older versions I only had to return a dictionary, but it has changed apparently.

1 Answers

Problem solved!

Looks like the problem was CO_NEWLOCAL flag. Accodring to the documentation:

If set, a new dict will be created for the frame’s f_locals when the code object is executed.

Sounds like exactly what I don't want to happen. Looking into CPython code there's exactly one place when this flag is set, when compiling function blocks. So, it seem like no function won't work here. Same for lambdas. But what about compile builtin?

>> compile('x = 99', '', 'exec').co_flags
64

Bingo! In the end it is the piece of code that solves my problem:

import types

class A:
  x = 13

print(A.x)

f = types.FunctionType(compile('x = y', '', 'exec'), globals={'y': 13})

B = __build_class__(f, 'B')
print(B.x)

Related