Если вы не доверяете глобальным переменным, когда вы находитесь внутри метода, как вы скажете, в каком классе мы сейчас находимся? - PullRequest
0 голосов
/ 01 ноября 2019

Это вопрос об общем принципе самоанализа. Когда вы находитесь внутри метода, как мы можем дать возможность определить, в каком классе мы сейчас находимся?

Мы хотим что-то вроде следующего:

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

Ответы [ 2 ]

2 голосов
/ 01 ноября 2019

В ссылочном интерпретаторе CPython вы можете получить класс, в котором был определен метод, просто сославшись на __class__:

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

Насколько мне известно, это деталь реализации CPython (он используется дляподдержка вызовов no-arg super(), и я не думаю, что это упоминается нигде, кроме как при передаче в журнале изменений и документации «Что нового»), поэтому не полагайтесь на это на других переводчиках.

Если выхотите тип времени выполнения (чтобы он сообщал тип подкласса даже при вызове метода, определенного в родительском объекте), используйте 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
0 голосов
/ 01 ноября 2019

Ниже приведено одно неуместное решение, но оно работает:

...