[python-brasil] Herança de propriedades

100 views
Skip to first unread message

José Alexandre Nalon

unread,
Feb 2, 2011, 12:51:04 PM2/2/11
to python...@yahoogrupos.com.br
Olá!

Uma dúvida rápida que me ocorreu durante a escrita de um módulo,
que não consegui pensar em uma solução óbvia. Suponhamos o códi-
go seguinte:

<code>
>>> class A(object):
... def __init__(self):
... self.__a = 1
... def __geta(self):
... return self.__a
... a = property(__geta, None)
...
>>> x = A()
>>> x.a
1
</code>

Desejo derivar essa classe em uma classe B. Essa classe tem a
mesma propriedade 'a', mas com a qual se trabalha separadamente.
O acesso à propriedade seria idêntico. Mas:

<code>
>>> class B(A):
... def __init__(self):
... A.__init__(self)
... self.__a = (1, 1)
...
>>> y = B()
>>> y.a
1
</code>

O acesso foi feito à variável da classe original, não da classe
derivada. Sei que é possível definir um setter para a proprieda-
de, mas esse é apenas um exemplo simplificado. Um setter não fun-
cionaria, por exemplo, se a propriedade fosse calculada, e não um
atributo de instância.

(Isso acontece porque a função, definida na classe A, acessa o
atributo _A__a, enquanto a atribuição na classe B é feita para o
atributo _B__a. Esse problema, na verdade, vai se extender sem-
pre que a classe B tentar acessar um atributo escondido da classe
A).

É possível solucionar esse problema copiando a definição da pro-
priedade para a classe derivada, mas isso mata completamente o pro-
pósito da herança. Haverá alguma maneira de fazer com que as fun-
ções que definem a propriedade? Consigo pensar em uma ou duas for-
mas de contornar, mas possivelmente existe uma boa maneira de fa-
zer isso.

---
José Alexandre Nalon
na...@terra.com.br


------------------------------------

Python-Brasil
http://www.python.org.br/wiki/AntesDePerguntar
Links do Yahoo! Grupos

<*> Para visitar o site do seu grupo na web, acesse:
http://br.groups.yahoo.com/group/python-brasil/

<*> Para sair deste grupo, envie um e-mail para:
python-brasi...@yahoogrupos.com.br

<*> O uso que você faz do Yahoo! Grupos está sujeito aos:
http://br.yahoo.com/info/utos.html


Eduardo Cereto Carvalho

unread,
Feb 2, 2011, 1:04:14 PM2/2/11
to python...@yahoogrupos.com.br
Humm vejo alguns problemas ai mas não sei se reolvem:

Para executar o __init__ de A dentro do __init__ de B tente usar o super
para manter o contexto.

super(B, self).__init__()

Do jeito que você está fazendo ele chama o __init__ como se fose um método
de classe.

Outra dica, talvez se você suar apenas um underscore na propriedade talvez
consiga compartilhar a propriedade entre pai e filho.

usar self._a ao inves de self.__a

Um underscore indica que você não deveria usar aquela variavel diretamente
enquanto que os 2 underscores te impedem realmente de usar, dependendo da
versão do python.

não tenho certeza se te resolve ou não.

2011/2/2 José Alexandre Nalon <na...@terra.com.br>

> na...@terra.com.br <nalon%40terra.com.br>
>
>

--
Eduardo Cereto Carvalho


[As partes desta mensagem que não continham texto foram removidas]

Thiago F. Pappacena

unread,
Feb 2, 2011, 1:10:59 PM2/2/11
to python...@yahoogrupos.com.br
2011/2/2 Eduardo Cereto Carvalho <eduard...@gmail.com>:

> Outra dica, talvez se você suar apenas um underscore na propriedade talvez
> consiga compartilhar a propriedade entre pai e filho.

Bem, pelo histórico do Nalon na lista, imagino que ele saiba dessa recomendação.

Assumindo isso, consigo imaginar uma maneira bem feia de resolver o
problema: fazendo com que o método original "__geta" fosse escrito de
um jeito mais ou menos assim:

clsname = cls.__class__.__name__
return getattr(self, '_%s__a' % clsname)

Obviamente, isso também não seria a implementação ideal. Mas pensando
bem, quem escreveu a classe A não parecia querer ter o atributo "__a"
alterado pelas subclasses mesmo... ;)

[]'s,
Thiago F. Pappacena

Desenvolver software é como dirigir um carro em alta velocidade, não
como atirar uma flexa.

José Alexandre Nalon

unread,
Feb 2, 2011, 1:44:42 PM2/2/11
to python...@yahoogrupos.com.br
Olá!

Em qua 02 fev 2011, às 16:04:14, você escreveu:
> Para executar o __init__ de A dentro do __init__ de B tente usar o super
> para manter o contexto.
>
> super(B, self).__init__()
>
> Do jeito que você está fazendo ele chama o __init__ como se fose um método
> de classe.

Obrigado pela resposta! Pessoalmente, sempre gostei muito mais
de usar o nome da classe mãe explicitamente, e creio que, exce-
to em situações mais patológicas (eg, herança múltipla em dia-
mante), é o mais recomendável.

Acredito que o super é realmente o caminho para a solução do
jeito mais pythonico, mas, infelizmente, isso ainda não é tra-
tado nessa função. Vejamos:

<code>
>>> class A(object):
... def __init__(self):
... self.__a = 1
... def __geta(self):
... return self.__a
... a = property(__geta, None)
...
>>> x = A()
>>> x.a
1

>>> class B(A):
... def __init__(self):

... super(B, self).__init__()


... self.__a = (1, 1)
...
>>> y = B()
>>> y.a
1
</code>

Uma pena, porque seria mais uma razão para usar a função. A
não ser, como disse antes, que eu esteja esquecendo alguma
coisa. :)

---
José Alexandre Nalon
na...@terra.com.br

José Alexandre Nalon

unread,
Feb 2, 2011, 1:49:07 PM2/2/11
to python...@yahoogrupos.com.br
Olá!

> Bem, pelo histórico do Nalon na lista, imagino que ele saiba dessa
> recomendação.

Obrigado pelo voto de confiança, mas -- apesar de conhecer essa pos-
siblidade em específico -- é bem capaz que eu seja um dos que menos
conhece a linguagem por aqui. :)

> Mas pensando
> bem, quem escreveu a classe A não parecia querer ter o atributo "__a"
> alterado pelas subclasses mesmo... ;)

Na verdade, existem, em alguns casos, justificativa para tanto. Por
exemplo, se o método __geta fosse complicado (muitas linhas), manter
uma versão na classe A e outra na classe B seria contraproducente e
difícil de manter. O acesso a atributos escondidos por subclasses é
coisa comum: em Java, por exemplo, corresponde ao atributo protected.
Python é 8 ou 80 nesse caso: ou o atributo é público, ou é privado.

---
José Alexandre Nalon
na...@terra.com.br

joão carlos

unread,
Feb 2, 2011, 1:53:13 PM2/2/11
to python...@yahoogrupos.com.br
Eu não endendi sua pergunta porque
x.a e y.a acessam apenas o método da classe A, pois a Classe B não existe nada chamado a, inclusive se você não herdar mais a classe A a chamada y.a irá retornar um erro que o atributo a não existe.
--- Em python...@yahoogrupos.com.br, José Alexandre Nalon <nalon@...> escreveu
> nalon@...

Thiago F. Pappacena

unread,
Feb 2, 2011, 2:14:02 PM2/2/11
to python...@yahoogrupos.com.br
2011/2/2 José Alexandre Nalon <na...@terra.com.br>

> > Mas pensando


> > bem, quem escreveu a classe A não parecia querer ter o atributo "__a"
> > alterado pelas subclasses mesmo... ;)
>
> Na verdade, existem, em alguns casos, justificativa para tanto. Por
> exemplo, se o método __geta fosse complicado (muitas linhas), manter
> uma versão na classe A e outra na classe B seria contraproducente e
> difícil de manter. O acesso a atributos escondidos por subclasses é
> coisa comum: em Java, por exemplo, corresponde ao atributo protected.
> Python é 8 ou 80 nesse caso: ou o atributo é público, ou é privado.
>

> Nalon,

a solução q eu apresentei deixa que o atributo "a" seja sobreescrito nas
subclasses, mas você acaba precisando alterar o código do método __geta na
class A. Você não precisaria ter o método __geta duplicado na classe B.
Executa só o exemplo: http://pastebin.com/2asPzShh

De qualquer forma, eu acho que não colocaria o atributo como "privado" desse
jeito. Colocaria com um único underline mesmo. Acho que nunca realmente
precisei esconder um atributo tanto assim em Python... ;)

[]'s,
Thiago F. Pappacena

Desenvolver software é como dirigir um carro em alta velocidade, não como
atirar uma flexa.

[As partes desta mensagem que não continham texto foram removidas]

------------------------------------

Leonardo Santagada

unread,
Feb 2, 2011, 3:02:02 PM2/2/11
to python...@yahoogrupos.com.br
2011/2/2 José Alexandre Nalon <na...@terra.com.br>:

> Obrigado pela resposta! Pessoalmente, sempre gostei muito mais
> de usar o nome da classe mãe explicitamente, e creio que, exce-
> to em situações mais patológicas (eg, herança múltipla em dia-
> mante), é o mais recomendável.
>

O problema é que não usando o super tu pode quebrar a compatibilidade
com herança multipla até para descendentes e usuários da classe se bem
me lembro. Eu nunca recomendaria usar o nome da classe pai e sempre a
usar o super.


--
Leonardo Santagada

Leonardo Santagada

unread,
Feb 2, 2011, 3:03:51 PM2/2/11
to python...@yahoogrupos.com.br
2011/2/2 José Alexandre Nalon <na...@terra.com.br>:

O jeito de resolver isso não é só trocando a ultima linha do init de b
para self._A__a = (1,1) ? porque __a é protegido/privado (um dos dois
nunca lembro qual) de clase então ele recebe o nome da classe que a
criou.


--
Leonardo Santagada

Pedro Werneck

unread,
Feb 2, 2011, 3:17:41 PM2/2/11
to python...@yahoogrupos.com.br
2011/2/2 Leonardo Santagada <sant...@gmail.com>

>
>
>
> 2011/2/2 José Alexandre Nalon <na...@terra.com.br>:
>
> > Olá!
> >
> > Em qua 02 fev 2011, às 16:04:14, você escreveu:
> >> Para executar o __init__ de A dentro do __init__ de B tente usar o super
> >> para manter o contexto.
> >>
> >>         super(B, self).__init__()
> >>
> >> Do jeito que você está fazendo ele chama o __init__ como se fose um método
> >> de classe.
> >
> > Obrigado pela resposta! Pessoalmente, sempre gostei muito mais
> > de usar o nome da classe mãe explicitamente, e creio que, exce-
> > to em situações mais patológicas (eg, herança múltipla em dia-
> > mante), é o mais recomendável.


Se essas são as dúvidas rápidas do Nalon, nem quero imaginar as demoradas...

Bom... isso é uma questão de consistência. Você está tentando pegar o
valor via property, mas defini-lo acessando diretamente. Não vai
funcionar. Se quer acessá-lo diretamente e pegar a classe correta,
terá inevitavelmente de fazer o "name mangling" na mão.

O jeito mais simples de resolver é definindo um setter também:


class A(object):
def __init__(self):
self.a = 1

def __geta(self):
return self.__a

def __seta(self, v):
self.__a = v

a = property(__geta, __seta)


class B(A):
def __init__(self):
A.__init__(self)
self.a = (1, 1)


Isso deve funcionar como esperado...

---
Pedro Werneck

José Alexandre Nalon

unread,
Feb 3, 2011, 12:41:21 PM2/3/11
to python...@yahoogrupos.com.br
Olá!

> Bom... isso é uma questão de consistência. Você está tentando pegar o
> valor via property, mas defini-lo acessando diretamente.

Veja que o uso de property foi apenas a situação em que ocorreu no
script que estava escrevendo. Isso vai acontecer também se for usa-
do um método qualquer. Mas acho que é fácil de justificar o compor-
tamento que eu desejava ver porque ele é o esperado intuitivamente:
os métodos de uma classe devem lidar com os seus próprios atributos,
e não com os atributos da classe mãe. Se um atributo for redefinido
na nova classe, os métodos herdados da classe original deveriam ser
capazes de lidar com essa modificação.

(O interessante é que isso não é realmente difícil de fazer: a su-
gestão do Thiago é perfeita, e provavelmente a mais simples. Infe-
lizmente, ela é pouco prática).

Vou explicar exatamente qual o meu caso: na classe mãe, define-se
uma matriz, que tem suas dimensões modificada na classe derivada.
Como um objeto novo precisa ser gerado, não é possível modificá-lo
in loco.

Por questões de eficiência, no entanto, é desejável utilizar o a-
tributo diretamente, pois isso é bem menos caro que acessar uma
propriedade -- significativamente em algoritmos iterativos. Infe-
lizmente, se o atributo é da classe original, ele não é acessível
na nova classe.

É possível solucionar esse problema através do name mangling, mas
acho essa alternativa pouco elegante. Se eu conhecesse o suficien-
te de Python, me atreveria a sugerir uma modificação na função
super -- ou talvez até uma função nova -- para lidar com esses
casos. No entanto, não me considero conhecedor o suficiente para
enfrentar o debate subsequente. :)

Em todo caso, agradeço a todos as respostas. Por alguns momentos,
tive medo que fosse uma coisa extremamente simples e que eu esti-
vesse perguntando algo que eu já deveria saber. :)

---
José Alexandre Nalon
na...@terra.com.br

Pedro Werneck

unread,
Feb 4, 2011, 8:42:42 AM2/4/11
to python...@yahoogrupos.com.br
2011/2/3 José Alexandre Nalon <na...@terra.com.br>

>
> Olá!
>
> > Bom... isso é uma questão de consistência. Você está tentando pegar o
> > valor via property, mas defini-lo acessando diretamente.
>
> Veja que o uso de property foi apenas a situação em que ocorreu no
> script que estava escrevendo. Isso vai acontecer também se for usa-
> do um método qualquer.

Vai acontecer porque você quer usar o recurso exatamente para fazer o
contrário do propósito original dele. Não faz sentido ocultar um
atributo para depois querer acessá-lo da subclasse. Name mangling
restringe realmente à classe, não à hierarquia.

> Mas acho que é fácil de justificar o compor-
> tamento que eu desejava ver porque ele é o esperado intuitivamente:
> os métodos de uma classe devem lidar com os seus próprios atributos,
> e não com os atributos da classe mãe. Se um atributo for redefinido
> na nova classe, os métodos herdados da classe original deveriam ser
> capazes de lidar com essa modificação.

O que acontece é que o name mangling é feito na hora da compilação do
método, não da execução, que parece ser o que você queria. A classe
onde o acesso foi escrito é aquela cujo nome vai ficar.

> (O interessante é que isso não é realmente difícil de fazer: a su-
> gestão do Thiago é perfeita, e provavelmente a mais simples. Infe-
> lizmente, ela é pouco prática).

A solução do Thiago é justamente fazer o name-mangling na hora da
execução, sabendo qual é a classe onde está ocorrendo o acesso.

> Vou explicar exatamente qual o meu caso: na classe mãe, define-se
> uma matriz, que tem suas dimensões modificada na classe derivada.
> Como um objeto novo precisa ser gerado, não é possível modificá-lo
> in loco.

Agora eu que me confundi. Essa matriz é um atributo da classe ou da
instância? Ao criar uma nova matriz de novas dimensões na instância da
classe derivada você não está modificando a matriz nas instâncias da
classe original.

> Por questões de eficiência, no entanto, é desejável utilizar o a-
> tributo diretamente, pois isso é bem menos caro que acessar uma
> propriedade -- significativamente em algoritmos iterativos. Infe-
> lizmente, se o atributo é da classe original, ele não é acessível
> na nova classe.
>
> É possível solucionar esse problema através do name mangling, mas
> acho essa alternativa pouco elegante.

Agora que você me confundiu um pouco, confesso que já nem sei mais
qual é o problema real. Usar name mangling não é solução para o
problema inicial que você deu pelo exemplo, é justamente o contrário.

> Se eu conhecesse o suficien te de Python, me atreveria a sugerir uma


> modificação na função super -- ou talvez até uma função nova -- para
> lidar com esses casos. No entanto, não me considero conhecedor o
> suficiente para enfrentar o debate subsequente. :)

Modificação de super não seria bem o caso. Como eu disse logo acima a
alteração do nome ocorre na compilação, então se o método que seta
self.__a está definido na classe, aquilo foi convertido para
self._A__a e estará assim em todas as subclasses a menos que o método
seja reescrito nelas, não importa o que ocorra. O que você quer é bem
mais complicado e duvido que haja alguma solução prática que não seja
significativamente mais cara do que usar um método de acesso.

Talvez o caminho para uma solução seja encontrar uma forma de dar um
bypass ou consertar a modificação do nome feita na compilação em algum
outro momento. Vou brincar um pouco com isso depois e vejo se chego a
algo prático.


> Em todo caso, agradeço a todos as respostas. Por alguns momentos,
> tive medo que fosse uma coisa extremamente simples e que eu esti-
> vesse perguntando algo que eu já deveria saber. :)

Pra ser sincero agora eu fiquei em dúvida se não é algo simples devido
àquela aparente confusão entre atributo de classe e de instância, mas
se não for o caso então é algo bastante complicado.


---
Pedro Werneck

Pedro Werneck

unread,
Feb 4, 2011, 12:53:52 PM2/4/11
to python...@yahoogrupos.com.br
2011/2/4 José Alexandre Nalon <na...@terra.com.br>
>
> Bom, talvez seja esse mesmo o problema. Mas a necessidade de fazer
> o que estou tentando existe. Independente do meu problema em espe-
> cífico: pode ser necessário a uma subclasse acessar um atributo es-
> condido da classe original. Olhando com cuidado, meu problema pode-
> ria ser resolvido de maneira mais simples se isso fosse possível.
> Se fiz alguma confusão, foi tentando contornar esse problema.

Sim, sua necessidade existe, mas a solução para ela não é com o
name-mangling, que é um recurso puramente sintático, não é um recurso
de encapsulamento.

O único caso que eu creio que name-mangling se aplica com segurança é
em properties, aplicando ao atributo e aos métodos, consistentemente.


> Atributo de instância. No __init__ da classe derivada eu preciso
> de uma matriz com características diferentes mas que se envolve nas
> mesmas operações. O atributo é escondido em ambas as classes porque
> o setter faz algumas checagens antes de realizar a atribuição. Sem
> a complicação do property, o que eu tenho, basicamente, é:
>
> <code>
> class A(object):
> def __init__(self):
> self.__w = ...
>
> class B(A):
> def __init__(self):
> super(B, self).__init__()
> self.__w = ...
> </code>
>
> Percebe como isso é contraintuitivo? Apesar de B() ser uma instância
> de A, possui dois atributos diferentes com o mesmo nome. Apenas um
> deles pode ser acessado, mas o mais adequado é que fossem o mesmo.
> É um comportamento diferente dos atributos não escondidos: se a va-
> riável de instância fosse 'w', o que quer que fosse definido na clas-
> se original seria perdido.

Sim, entendo, mas continuo confuso quanto ao que exatamente você quer.
Considerando x uma instancia de A, e y uma instancia de B, você quer
que x._A__w, y._A__w e y._B__w existam, que x._A__w e y._B__w sejam
acessiveis através de x.__w e y.__w, mas que y._A__w continue
disponivel com o valor que é atribuido no A.__init__ se for tentar
acessar construindo o nome completo?


> > Vou brincar um pouco com isso depois e vejo se chego a
> > algo prático.
>

> Certamente eu gostaria de ver isso. :) Pensei em brincar um pouco
> com a solução que o Thiago enviou e criar uma metaclasse (Protected)
> que permitisse a 'publicação' de atributos escondidos a subclasses.
> Mas metaclasses me dão medo, nunca sei se é exagero solucionar os
> problemas dessa maneira.

Metaclasses aqui não ajudam muito a não ser para injetar a solução
depois de pronta. Como eu disse antes, o name-mangling acontece na
compilação, então a função já chega na metaclasse com os nomes
modificados. Para fazer isso com metaclasses você teria de mexer com
__setatr__ e __getattribute__, o que teria um impacto muito maior do
que o que você deseja.

Você pode fazer uma metaclasse que recria as funções nas subclasses
alterando o nome armazenado. Seria como você mesmo estar redefinindo
todas na mão, mas automatizado. É uma opção. Aliás, pensando bem nisso
parece uma ótima opção. Vou tentar algo nesse sentido depois. :)

José Alexandre Nalon

unread,
Feb 4, 2011, 11:34:26 AM2/4/11
to python...@yahoogrupos.com.br
Olá!

> Vai acontecer porque você quer usar o recurso exatamente para fazer o
> contrário do propósito original dele. Não faz sentido ocultar um
> atributo para depois querer acessá-lo da subclasse. Name mangling
> restringe realmente à classe, não à hierarquia.

Bom, talvez seja esse mesmo o problema. Mas a necessidade de fazer


o que estou tentando existe. Independente do meu problema em espe-
cífico: pode ser necessário a uma subclasse acessar um atributo es-
condido da classe original. Olhando com cuidado, meu problema pode-
ria ser resolvido de maneira mais simples se isso fosse possível.
Se fiz alguma confusão, foi tentando contornar esse problema.

> Agora eu que me confundi. Essa matriz é um atributo da classe ou da


> instância? Ao criar uma nova matriz de novas dimensões na instância da
> classe derivada você não está modificando a matriz nas instâncias da
> classe original.

Atributo de instância. No __init__ da classe derivada eu preciso


de uma matriz com características diferentes mas que se envolve nas
mesmas operações. O atributo é escondido em ambas as classes porque
o setter faz algumas checagens antes de realizar a atribuição. Sem
a complicação do property, o que eu tenho, basicamente, é:

<code>
class A(object):
def __init__(self):
self.__w = ...

class B(A):
def __init__(self):
super(B, self).__init__()
self.__w = ...
</code>

Percebe como isso é contraintuitivo? Apesar de B() ser uma instância
de A, possui dois atributos diferentes com o mesmo nome. Apenas um
deles pode ser acessado, mas o mais adequado é que fossem o mesmo.
É um comportamento diferente dos atributos não escondidos: se a va-
riável de instância fosse 'w', o que quer que fosse definido na clas-
se original seria perdido.

> Vou brincar um pouco com isso depois e vejo se chego a
> algo prático.

Certamente eu gostaria de ver isso. :) Pensei em brincar um pouco


com a solução que o Thiago enviou e criar uma metaclasse (Protected)
que permitisse a 'publicação' de atributos escondidos a subclasses.
Mas metaclasses me dão medo, nunca sei se é exagero solucionar os
problemas dessa maneira.

Pensei que, talvez, um atributo de classe pudesse conter os nomes
das variáveis escondidas que pudessem ser acessadas pelas subclasses.
Algo como o __slots__: um atributo __protected__ ou coisa semelhan-
te.

(Tentei ver se o próprio __slots__ não resolvia isso como efeito
colateral, mas descobri que a subclasse também não respeita o
__slots__! No entanto, creio que, se isso for um problema, é bem
menor, e a necessidade de adicionar variáveis em subclasses jus-
tifica o comportamento.)

> Pra ser sincero agora eu fiquei em dúvida se não é algo simples devido
> àquela aparente confusão entre atributo de classe e de instância, mas
> se não for o caso então é algo bastante complicado.

Eu procuro evitar atributos de classe onde possível, então não creio
que exista essa confusão. Acho que o principal problema, realmente,
é que subclasses não podem mexer nos atributos da classe original.

---
José Alexandre Nalon
na...@terra.com.br

José Alexandre Nalon

unread,
Feb 4, 2011, 1:21:23 PM2/4/11
to python...@yahoogrupos.com.br
Olá!

> Sim, sua necessidade existe, mas a solução para ela não é com o
> name-mangling,

Sim, e eu quero evitar name-mangling de qualquer maneira. :)
Apenas me ocorreu que, dadas as características da implemen-
tação das instâncias em Python como elas são atualmente, is-
so (possivelmente) seria a solução mais prática -- mas ainda
assim não desejável. Não me agrada muito mexer nas entranhas
da linguagem dessa maneira.

> Considerando x uma instancia de A, e y uma instancia de B, você quer
> que x._A__w, y._A__w e y._B__w existam, que x._A__w e y._B__w sejam
> acessiveis através de x.__w e y.__w, mas que y._A__w continue
> disponivel com o valor que é atribuido no A.__init__ se for tentar
> acessar construindo o nome completo?

Não, não. Que y._A__w e y._B__w sejam a mesma variável. Assim,
se eu acesso y.__w na classe mãe ou na subclasse, o mesmo obje-
to seja acessado; se eu faço uma atribuição em y.__w tanto na
classe mãe quanto na subclasse, a modificação fosse sentida em
ambas as classes. Valores antigos não me interessam.

Esse é o comportamento de uma variável de instância pública.
Suponha que, ao invés de .__w, fosse .w. Não importa em qual
classe esteja o método que altera essa variável, a mudança é
sentida em métodos de ambas as classes. Veja:

<code>
>>> class A(object):
... def __init__(self):

... self.w = 1
... def show(self):
... print self.w
...

>>> class B(A):
... def __init__(self):

... self.w = (1, 1)
...
>>> b = B()
>>> b.show()
(1, 1)
</code>

Eu gostaria que isso pudesse ser feito para atributos escondi-
dos em subclasses. Veja que eu não questiono a forma como o
Python implementa a privacidade de atributos -- muito pelo con-
trário, eu gosto disso. Mas em algumas situações, permitir o
acesso controlado é útil.

> Você pode fazer uma metaclasse que recria as funções nas subclasses
> alterando o nome armazenado.

Nem vou tentar. :D Metaclasses são magia negra profunda demais
pra mim, e eu tenho medo de acordar algum demônio muito podero-
so que possa causar a destruição do mundo. (Pode ser que até o
final do ano que vem eu mude de ideia em relação a isso, quem
sabe?)

---
José Alexandre Nalon
na...@terra.com.br

Pedro Werneck

unread,
Feb 4, 2011, 1:34:20 PM2/4/11
to python...@yahoogrupos.com.br
2011/2/4 José Alexandre Nalon <na...@terra.com.br>
[corta]

> > Considerando x uma instancia de A, e y uma instancia de B, você quer
> > que x._A__w, y._A__w e y._B__w existam, que x._A__w e y._B__w sejam
> > acessiveis através de x.__w e y.__w, mas que y._A__w continue
> > disponivel com o valor que é atribuido no A.__init__ se for tentar
> > acessar construindo o nome completo?
>
> Não, não. Que y._A__w e y._B__w sejam a mesma variável. Assim,
> se eu acesso y.__w na classe mãe ou na subclasse, o mesmo obje-
> to seja acessado; se eu faço uma atribuição em y.__w tanto na
> classe mãe quanto na subclasse, a modificação fosse sentida em
> ambas as classes. Valores antigos não me interessam.

Ué... se é isso então por que não usar simplesmente y._w ? Ou usar
property com getter e setter mantendo ambos em A e continuar sendo
y._A__w? Qualquer das soluções funciona como você quer.


---
Pedro Werneck

José Alexandre Nalon

unread,
Feb 4, 2011, 2:42:41 PM2/4/11
to python...@yahoogrupos.com.br
Olá!

> Ué... se é isso então por que não usar simplesmente y._w ? Ou usar
> property com getter e setter mantendo ambos em A e continuar sendo
> y._A__w? Qualquer das soluções funciona como você quer.

Prefiro deixar o atributo privado. Como eu falei, preciso fazer
alguns ajustes antes da atribuição. Ainda que o zen do Python
diga que explícito é melhor que implícito, eu prefiro, se possí-
vel, não deixar a porta aberta para que o usuário faça a atri-
buição direta. Pode evitar alguns dissabores.

Por outro lado, y._A__w é feio demais pra ser usado. Sinto mui-
to, mas legibilidade conta. Eu já não sou muito fã de usar os
dois underscores, mas pelo menos, depois de acostumar, eles
passam sem serem notados. Além disso, se a hierarquia de clas-
ses começar a crescer demais, essa solução pode muito mais com-
plicar que simplificar.

De qualquer forma, eu resolvi de uma forma diferente: reimple-
mentei o que precisava na classe derivada -- minha necessidade
é, por enquanto, pequena. Note que isso não muda o fato que o
recurso é útil.

---
José Alexandre Nalon
na...@terra.com.br

Paul Eipper

unread,
Feb 4, 2011, 6:43:38 PM2/4/11
to python...@yahoogrupos.com.br
2011/2/4 José Alexandre Nalon <na...@terra.com.br>:

> Olá!
>
>> Ué... se é isso então por que não usar simplesmente y._w ? Ou usar
>> property com getter e setter mantendo ambos em A e continuar sendo
>> y._A__w? Qualquer das soluções funciona como você quer.
>
> Prefiro deixar o atributo privado. Como eu falei, preciso fazer
> alguns ajustes antes da atribuição. Ainda que o zen do Python
> diga que explícito é melhor que implícito, eu prefiro, se possí-
> vel, não deixar a porta aberta para que o usuário faça a atri-
> buição direta. Pode evitar alguns dissabores.

Mas name mangling não é para deixar um atributo privado, aliás, nem
existe isso em Python. A convenção é que atributos com um underscore
não são para ser mexidos diretamente. Só isso. Name mangling é para
casos específicos (como para evitar colisão de nomes em subclasses), e
não para controle de acesso.
http://docs.python.org/tutorial/classes.html#private-variables

> Por outro lado, y._A__w é feio demais pra ser usado. Sinto mui-
> to, mas legibilidade conta. Eu já não sou muito fã de usar os
> dois underscores, mas pelo menos, depois de acostumar, eles
> passam sem serem notados. Além disso, se a hierarquia de clas-
> ses começar a crescer demais, essa solução pode muito mais com-
> plicar que simplificar.
>
> De qualquer forma, eu resolvi de uma forma diferente: reimple-
> mentei o que precisava na classe derivada -- minha necessidade
> é, por enquanto, pequena. Note que isso não muda o fato que o
> recurso é útil.

Particularmente, não vejo a utilidade. O fato é que você está usando
um recurso da linguagem com a expectativa de que ele faça outra coisa,
aí vai ficar feio mesmo :P

--
Paul Eipper

Joao S. O. Bueno

unread,
Feb 4, 2011, 9:35:08 PM2/4/11
to python...@yahoogrupos.com.br
Nalon --

de fato, não vejo sentido nisso de insistir tanto em "o atributo tem
que ser privado, e por isso
tem que começar com "__" "
Se você que rum atributo que o usuário não acesse dirtametne, ponha-o
dentor de um proeprty, mas
não é só por que está dentro de um property que o nome do atributo
real tem que começar com "__"
-
pode coemçar com qualquer coisa,
Pode ser
A._nao_mexa_aqui_w

Se você quiser mesmo levantar uma exceção se o usuári insistir em
mudar o atributo
A._nao_mexa_aqui_w,isso pode ser feito usando introspeção em frames - mas
acho que o usuário já foi suficientemente avisado (claro que não com
um nome desses,
mas simplesmente com ._w )

(Agora eu nunca tinha parado para pensar que o name mangling acontece
em tempo de
compilação...OMG - -acho que é a maior r gambiarra que já vi no Python
- tipo, de deixar
a implementação de 1º de abril do goto e comefrom algo bonito.


js
-><-


2011/2/4 Paul Eipper <lkra...@gmail.com>:


> 2011/2/4 José Alexandre Nalon <na...@terra.com.br>:
>> Olá!
>>

José Alexandre Nalon

unread,
Feb 4, 2011, 11:02:51 PM2/4/11
to python...@yahoogrupos.com.br
Olá!

> Mas name mangling não é para deixar um atributo privado, aliás, nem
> existe isso em Python.

Juro por deus que estou procurando nas minhas mensagens onde eu
falo que eu _quero_ fazer name mangling e não encontro. Lembro
muito bem de falar que quero evitar isso.

Há um outro motivo para você desejar não dar acesso direto a um
atributo: controle, para que o acesso ao atributo não seja fei-
to arbitrariamente. Sim, um usuário dedicado vai saber contornar
isso. O objetivo, nesse caso, não é impedir o acesso à variável
de instância -- é fornecer uma interface confiável a ela. Se o
acesso à variável de instância é público, essa confiabilidade
vai para o lixo. Considerando que, particularmente no meu caso,
o efeito dessa perda vai aparecer muitas e muitas linhas depois,
a depuração do programa acaba se tornando muito mais difícil do
que deveria ser.

> Particularmente, não vejo a utilidade. O fato é que você está usando
> um recurso da linguagem com a expectativa de que ele faça outra coisa,
> aí vai ficar feio mesmo :P

Não... eu não estou usando o recurso da linguagem porque ele não
existe na linguagem. Veja, eu já afirmei que solucionei o proble-
ma por outras vias, e não está feio, está pythonico, etc. O que
me incomoda é que poderia ser _mais_ elegante se o recurso exis-
tisse.

---
José Alexandre Nalon
na...@terra.com.br

Leonardo Santagada

unread,
Feb 5, 2011, 6:29:46 AM2/5/11
to python...@yahoogrupos.com.br
2011/2/5 José Alexandre Nalon <na...@terra.com.br>:

> Há um outro motivo para você desejar não dar acesso direto a um
> atributo: controle, para que o acesso ao atributo não seja fei-
> to arbitrariamente. Sim, um usuário dedicado vai saber contornar
> isso. O objetivo, nesse caso, não é impedir o acesso à variável
> de instância -- é fornecer uma interface confiável a ela.

Pra isso um _ só é suficiente, como outros já falaram.


--
Leonardo Santagada

Reply all
Reply to author
Forward
0 new messages