Как / почему глобальные переменные доступны / находятся в области видимости во вложенных экземплярах классов, а «нелокальные» переменные нет? - PullRequest
3 голосов
/ 09 марта 2019

Как получить доступ к OuterClass переменным аналогично тому, как осуществляется доступ к глобальным переменным?

Например:

global_variable = 'global_variable'

class InnerClass:

    def __init__(self):
        pass

    def test(self):
        return super().variable

    def test_global(self):
        return global_variable


class OuterClass:

    def __init__(self, inner_class_instance):
        self.variable = 'class_variable'
        self.inner_class_instance = inner_class_instance

Запуск приведенного ниже возвращает глобальную переменную:

inner = InnerClass()
outer = OuterClass(inner)
outer.inner_class_instance.test_global()

Однако попытка доступа к переменной класса nonlocal приводит к AttributeError:

outer.inner_class_instance.test()

super() неправильно используется в InnerClass.test, так как OuterClass не является базойкласс для InnerClass.Как получить доступ к OuterClass переменным аналогично тому, как осуществляется доступ к глобальным переменным?Это без передачи аргумента контекста InnerClass.Использование nonlocal variable в InnerClass.test привело к SyntaxError.

Кроме того, как и почему глобальная переменная доступна из InnerClass.test?

Ответы [ 3 ]

1 голос
/ 09 марта 2019

В test(self) методе InnerClass вы неправильно поняли значение выражения super().variable.super() здесь относится к суперклассу InnerClass, который (хотя и не явный в коде) является предопределенным классом, называемым Object.И класс Object определенно не имеет атрибута с именем variable.И именно поэтому в этой строке выдается ошибка

У «супер» объекта нет атрибута «переменная»

Ваш другой вопрос был - «Как получить доступ OuterClassпеременные?».

Я хотел бы сначала прояснить некоторые основные аспекты понятий здесь.

Прежде всего, то, что у вас внутри InnerClass и имеет имя variable, на самом деле атрибут из InnerClass.Поэтому я бы лучше перефразировал ваш вопрос как «Как получить доступ к OuterClass атрибутам из метода InnerClass?».

Во-вторых, только потому, что OuterClass получаетссылка на экземпляр InnerClass, когда выполняется __init__() метод OuterClass, не означает, что OuterClass каким-либо образом является "внешним по отношению к" или "окружает" InnerClass.

С точки зрения кода в InnerClass, OuterClass - это просто другой класс, без особого статуса - он не является ни суперклассом (классом-предком), ни внешним классом (окружающим классом).Следовательно, чтобы получить доступ к атрибуту экземпляра OuterClass, из метода InnerClass, называемого test(), сначала нужно имя, которое содержит ссылку на экземпляр OuterClass.Так, например, в методе test(), если у вас есть имя с именем my_outer_inst, которое содержит ссылку на экземпляр OuterClass, вы, безусловно, можете обратиться к атрибуту OuterClass с именем variable,используя my_outer_inst.variable.

0 голосов
/ 09 марта 2019

Как правило, экземпляр, назначенный в качестве атрибута какого-либо другого экземпляра, не может получить ссылку на содержащий экземпляр.С одной стороны, может быть ноль или более одной такой ссылки!Например, если вы создали второй экземпляр OuterClass с тем же экземпляром InnerClass, то будет два потенциально разных атрибута variable, которые вы, возможно, захотите прочитать.

В общем, если вы хотитечтобы получить доступ к атрибутам объекта, вам сначала нужна ссылка на объект.Одной ссылки на вас недостаточно, если только вы не устроите какой-нибудь альтернативный API.

Например, возможно, InnerClass ожидает получить ссылку на OuterClass в своем методе test и OuterClass получает метод для передачи себя:

class InnerClass:
    def test(self, outer):
        return outer.variable

class OuterClass:
    def __init__(self, inner, variable):
        self.inner = inner
        self.variable = variable

    def run_test(self):
        return self.inner.test(self)

out = OuterClass(InnerClass(), "foo")
print(out.run_test())

Вы также можете настроить классы на циклические ссылки, где каждый из них ссылается друг на друга.Тогда любой из них может делать что-то с другим:

class InnerClass:
    def __init__(self):
        self.outer = None

    def test(self):
        if self.outer is None:
            raise ValueError("Not in an OuterClass instance!")
        return self.outer.variable

 class OuterClass:
    def __init__(self, inner, variable):
        self.inner = inner
        inner.outer = self      # set reference back to us!
        self.variable = variable

out = OuterClass(InnerClass(), "foo")
print(out.inner.test())

Это очень грубая версия такого подхода, вы можете убедиться, что ваши ссылки остаются согласованными (не позволяя использовать тот же экземпляр InnerClass).например, двумя различными экземплярами OuterClass.

Обратите внимание, что подобные циклические ссылки усложняют работу сборщика мусора.Обычно объекты Python очищаются сразу после исчезновения их последней ссылки.Но объекты с циклами ссылок всегда имеют ссылки, идущие между собой, и поэтому GC должен проверить, не мертв ли ​​весь набор объектов вместе.Вероятно, он справится с этим довольно хорошо для цикла, который содержит всего два объекта, как в этом примере, но в более крупной структуре данных это может быть сложнее.

0 голосов
/ 09 марта 2019

Начиная с вашего первого вопроса, в коде для variable есть что-то еще, что нужно определить. AttributeError говорит ''super' object has no attribute 'variable'', означает, что оно не определено внутри класса.

Попробуйте выполнить это, inner.test(). Вы снова получаете то же самое AttributeError. Определите / Объявите variable и попробуйте один раз.

Второй вопрос, global переменные, которые объявлены вне класса. К ним можно получить доступ где угодно. Однако, чтобы изменить его значение, оно должно быть объявлено как global var_name внутри класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...