Область вложенных классов?
Я пытаюсь понять область применения вложенных классов в Python. Вот мой пример кода:
class OuterClass:
outer_var = 1
class InnerClass:
inner_var = outer_var
Создание класса не завершено, и я получаю ошибку:
<type 'exceptions.NameError'>: name 'outer_var' is not defined
Попытка inner_var = Outerclass.outer_var
не работает.
Я получаю:
<type 'exceptions.NameError'>: name 'OuterClass' is not defined
Я пытаюсь получить доступ к статическому outer_var
из InnerClass
.
Есть ли способ сделать это?
Ответы
Ответ 1
class Outer(object):
outer_var = 1
class Inner(object):
@property
def inner_var(self):
return Outer.outer_var
Это не совсем то же самое, что аналогичные вещи работают на других языках и использует глобальный поиск вместо того, чтобы просматривать доступ к outer_var
. (Если вы измените объект, к которому привязано имя Outer
, тогда этот код будет использовать этот объект при следующем его выполнении.)
Если вы хотите, чтобы все объекты Inner
имели ссылку на Outer
, потому что outer_var
действительно является атрибутом экземпляра:
class Outer(object):
def __init__(self):
self.outer_var = 1
def get_inner(self):
return self.Inner(self)
# "self.Inner" is because Inner is a class attribute of this class
# "Outer.Inner" would also work, or move Inner to global scope
# and then just use "Inner"
class Inner(object):
def __init__(self, outer):
self.outer = outer
@property
def inner_var(self):
return self.outer.outer_var
Обратите внимание, что классы вложенности несколько необычны в Python и не подразумевают автоматически какие-либо особые отношения между классами. Тебе лучше не гнездиться. (Вы все равно можете установить атрибут класса на Outer
до Inner
, если хотите.)
Ответ 2
Я думаю, вы можете просто сделать:
class OuterClass:
outer_var = 1
class InnerClass:
pass
InnerClass.inner_var = outer_var
Проблема, с которой вы столкнулись, связана с этим:
Блок представляет собой часть текста программы Python, которая выполняется как единое целое. Ниже приведены блоки: модуль, тело функции и класс определение.
(...)
Область определяет видимость имени внутри блок.
(...)
Объем имен, определенных в блоке класса, ограничивается блоком класса; он не распространяется на кодовые блоки методы - это включает выражения генератора, так как они реализован с использованием области функций. Это означает, что не в состоянии:
class A:
a = 42
b = list(a + i for i in range(10))
http://docs.python.org/reference/executionmodel.html#naming-and-binding
Вышеуказанное означает:
тело функции является блоком кода, а метод является функцией, тогда имена, определенные из тела функции, присутствующие в определении класса, не распространяются на тело функции.
Перефразируя это для вашего случая:
определение класса является кодовым блоком, тогда имена, определенные из определения внутреннего класса, присутствующие во внешнем определении класса, не распространяются на определение внутреннего класса.
Ответ 3
Вам может быть лучше, если вы просто не используете вложенные классы. Если вы должны вложить, попробуйте следующее:
x = 1
class OuterClass:
outer_var = x
class InnerClass:
inner_var = x
Или объявите оба класса перед их вложением:
class OuterClass:
outer_var = 1
class InnerClass:
inner_var = OuterClass.outer_var
OuterClass.InnerClass = InnerClass
(После этого вы можете del InnerClass
, если вам нужно.)
Ответ 4
Самое простое решение:
class OuterClass:
outer_var = 1
class InnerClass:
def __init__(self):
self.inner_var = OuterClass.outer_var
Это требует от вас быть явным, но не требует больших усилий.
Ответ 5
В Python изменяемые объекты передаются как ссылка, поэтому вы можете передать ссылку внешнего класса во внутренний класс.
class OuterClass:
def __init__(self):
self.outer_var = 1
self.inner_class = OuterClass.InnerClass(self)
print('Inner variable in OuterClass = %d' % self.inner_class.inner_var)
class InnerClass:
def __init__(self, outer_class):
self.outer_class = outer_class
self.inner_var = 2
print('Outer variable in InnerClass = %d' % self.outer_class.outer_var)
Ответ 6
Все объяснения можно найти в документации Python. Учебное пособие по Python
Для вашей первой ошибки <type 'exceptions.NameError'>: name 'outer_var' is not defined
. Объяснение:
Нет никаких сокращений для привязки атрибутов данных (или других методов!) из методов. Я нахожу, что это на самом деле увеличивает читаемость методов: нет возможности запутать локальные переменные и переменные экземпляра при просмотре метода.
приведенный в The Python Tutorial 9.4
Для вашей второй ошибки <type 'exceptions.NameError'>: name 'OuterClass' is not defined
Когда определение класса остается в норме (через конец), создается объект класса.
приведенный в учебнике по Python 9.3.1
Итак, когда вы пытаетесь inner_var = Outerclass.outer_var
, Quterclass
еще не создан, поэтому name 'OuterClass' is not defined
Более подробное, но утомительное объяснение вашей первой ошибки:
Хотя классы имеют доступ к охватывающим областям функций, хотя они не действуют как охватывающие области для кода, вложенные в класс: Python ищет закрывающие функции для ссылочных имен, но никогда никаких закрывающих классов. То есть, класс является локальной областью и имеет доступ к закрывающим локальным областям, но он не служит закрывающей локальной областью для дальнейшего вложенного кода.
цитируется в Learning.Python(5th).Mark.Lutz