如果你不信任全局变量,当你在一个方法内部时,你如何知道我们当前在哪个类?



这是一个关于内省的一般原则的问题。当你在一个方法内部时,我们如何才能说出我们当前所在的类?

我们想要如下的东西:

class FigNewton:
def baz(self):
current_class = MAGIC()

MAGIC是什么?以下情况是不可接受的,因为我们在一个不信任调用时全局变量的环境中工作。定义时的全局变量是受信任的,但在方法调用时不受信任。

class FigNewton:
def baz(self):
current_class = FigNewton

为什么在调用时不信任全局变量?因为像以下这样的恶作剧:

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()

输出为:

17995730
683010982
27999997387

而不是预期的:

apple
banana
current_class == FigNewton

以下是演示问题的更多代码:

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)

输出为:

--------------------------------------------------------------------------------
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
--------------------------------------------------------------------------------

在CPython引用解释器中,您可以通过简单地引用__class__:来获得方法定义的类

class FigNewton:
def baz(self):
current_class = __class__  # Assigns FigNewton, even if instance of subclass is used to invoke method

据我所知,这是CPython的一个实现细节(它用于支持无argsuper()调用,我认为除了在传递变更日志和What's New文档之外,其他地方都没有提到它(,所以不要依赖其他解释器。

如果您想要运行时类型(因此即使在父级中定义的方法中调用时,它也会报告子类类型(,请使用type(self)(或等效的self.__class__(:

class FigNewton:
def baz(self):
current_class = type(self)  # Assigns FigNewton or a subclass thereof if instance of subclass is used to invoke method

以下是一个笨拙的解决方案,但它有效:

class FigNewton:
def baz(self):
current_class = type(self).FigNewton
FigNewton.FigNewton = FigNewton

相关内容

最新更新