This is a question about the general principle of introspection. When you are inside of a method, how can we make it possible to tell what class we are currently in?
We want something like as follows:
class FigNewton:
def baz(self):
current_class = MAGIC()
What would MAGIC
be? The following is unacceptable, as we are working in an environment where call-time globals are not trusted. Globals at definition-time are trusted, but not globals at time-of-method-call.
class FigNewton:
def baz(self):
current_class = FigNewton
Why are globals not trusted at time-of-call? Because of shenanigans like the following:
class FigNewton:
def baz(self):
current_class = FigNewton
print("banana")
print("current_class ==", current_class.__name__)
import itertools
import string
print = lambda *args, print=print:\
print(
sum(
map(
lambda stryng:\
int(''.join(
itertools.takewhile(
lambda ch: ch in string.ascii_lowercase
,
stryng
)
), base=36)
,
map(str, args)
)
, )
)
print("apple")
obj = FigNewton()
FigNewton = "apple"
obj.baz()
The output is:
17995730
683010982
27999997387
Instead of the expected:
apple
banana
current_class == FigNewton
Below is more code demonstrating the problem:
class K0:
print=print
type=type
def foo(self, *args):
self.print(40 * "--")
self.print('args == ', args)
self.print("K0 version of foo is executing.")
self.print("Are all references to class K0 lost?")
self.print("Well, global label `K0` is ", self.type(K0).__qualname__, K0)
# K0.__getattribute__(self, "whatever") ## ERROR!!!
tsqn = self.type(self).__qualname__
self.print(
"type(self) is ", tsqn,
". Is that K0? ", ("yes" if tsqn == "K0" else "no"),
sep=""
)
self.print(40 * "--")
##########################################################
def test(seed_class):
Ks = [seed_class]
for idx in (1, 2, 3):
K = type("K{}".format(idx), (Ks[-1],), dict())
Ks.append(K)
class K4(Ks[-1]):
def foo(self):
print("K10 version of foo is executing")
print("type(self) is ", type(self))
# Begin messing up global namespace
global K0
K0 = 0
# End messing up global namespace
Ks.pop(0)
for K in Ks:
obj = K()
obj.foo(1, 2, 3)
return None
##########################################################
test(K0)
The output is:
--------------------------------------------------------------------------------
args == (1, 2, 3)
K0 version of foo is executing.
Are all references to class K0 lost?
Well, global label `K0` is int 0
type(self) is K1. Is that K0? no
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
args == (1, 2, 3)
K0 version of foo is executing.
Are all references to class K0 lost?
Well, global label `K0` is int 0
type(self) is K2. Is that K0? no
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
args == (1, 2, 3)
K0 version of foo is executing.
Are all references to class K0 lost?
Well, global label `K0` is int 0
type(self) is K3. Is that K0? no
--------------------------------------------------------------------------------