class Outer(object):
outer_var = 1
class Inner(object):
@property
def inner_var(self):
return Outer.outer_var
Isso não é exatamente o mesmo que coisas semelhantes funcionam em outras linguagens e usa pesquisa global em vez de definir o escopo de acesso outer_var
. (Se você mudar qual objeto o nomeOuter
está vinculado, este código usará esse objeto na próxima vez que for executado.)
Se, em vez disso, você quiser que todos os Inner
objetos tenham uma referência a um Outer
porque outer_var
é realmente um atributo de instância:
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
Observe que o aninhamento de classes é um tanto incomum em Python e não implica automaticamente em qualquer tipo de relacionamento especial entre as classes. É melhor você não aninhar. (Você ainda pode definir um atributo de classe Outer
para Inner
, se quiser.)
Outer
é pesquisada novamente toda vez que você o fazInner.inner_var
. Portanto, se você religar o nomeOuter
a um novo objeto,Inner.inner_var
começará a retornar esse novo objeto.Acho que você pode simplesmente fazer:
O problema que você encontrou é devido a este:
O acima significa:
um corpo de função é um bloco de código e um método é uma função, então os nomes definidos fora do corpo da função presente em uma definição de classe não se estendem ao corpo da função.
Parafraseando isso para o seu caso:
uma definição de classe é um bloco de código, então os nomes definidos fora da definição de classe interna presente em uma definição de classe externa não se estendem para a definição de classe interna.
fonte
[a + i for i in range(10)]
vincula Ab à lista esperada [42..51].list(a + i for i in range(10))
é olist((a + i for i in range(10)))
que quer dizerlist(a_generator)
. Eles dizem que um gerador é implementado com um escopo semelhante ao escopo das funções.list(...)
chamada nem a compreensão funcionam no Python 3. A documentação para Py3 também é um pouco diferente refletindo isso. Agora diz: " O escopo dos nomes definidos em um bloco de classe é limitado ao bloco de classe; não se estende aos blocos de código de métodos - isso inclui compreensões e expressões geradoras, uma vez que são implementados usando um escopo de função. " (Ênfase minha )Você pode ficar melhor se simplesmente não usar classes aninhadas. Se você deve aninhar, tente isto:
Ou declare ambas as classes antes de aninhá-las:
(Depois disso, você pode
del InnerClass
se precisar.)fonte
Solução mais fácil:
Exige que você seja explícito, mas não exige muito esforço.
fonte
Em Python, objetos mutáveis são passados como referência, portanto, você pode passar uma referência da classe externa para a classe interna.
fonte
__del__
método, o coletor de lixo não será capaz de lidar com o ciclo de referência e os objetos entrarãogc.garbage
. O código acima, como está, não é problemático. A maneira de lidar com isso é usando uma referência fraca . Você pode ler a documentação sobre fracaref (2.7) ou fracaref (3.5)Todas as explicações podem ser encontradas na documentação do Python. O tutorial do Python
Por seu primeiro erro
<type 'exceptions.NameError'>: name 'outer_var' is not defined
. A explicação é:citado em The Python Tutorial 9.4
Para o seu segundo erro
<type 'exceptions.NameError'>: name 'OuterClass' is not defined
citado em The Python Tutorial 9.3.1
Então, quando você tenta
inner_var = Outerclass.outer_var
, oQuterclass
ainda não foi criado, é por issoname 'OuterClass' is not defined
Uma explicação mais detalhada, mas entediante, para seu primeiro erro:
citado em Learning.Python (5º) .Mark.Lutz
fonte