Pergunta

Estou acostumado a esse Python permite alguns truques legais para delegar a funcionalidade a outros objetos. Um exemplo é a delegação em objetos contidos.

Mas se costuma, que não tenho sorte, quando quero delegar __ contém __:

class A(object):
    def __init__(self):
       self.mydict = {}
       self.__contains__ = self.mydict.__contains__

a = A()
1 in a

Eu recebo:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: argument of type 'A' is not iterable

O que estou entendendo errado? Quando eu chamo A .__ contém __ (1), tudo corre bem. Eu até tentei definir um método __iter __ em A para fazer uma aparência mais iterável, mas não ajudou. O que estou perdendo aqui?

Foi útil?

Solução

Métodos especiais como __contains__ só são especiais quando definidos na classe, não na instância (exceto nas aulas herdadas no Python 2, que você deve não use de qualquer maneira).

Então, faça sua delegação no nível da aula:

class A(object):
    def __init__(self):
       self.mydict = {}

    def __contains__(self, other):
       return self.mydict.__contains__(other)

Eu realmente prefiro soletrar o último como return other in self.mydict, mas essa é uma questão de estilo menor.

Editar: Se e quando "redirecionamento totalmente dinâmico por instancia embrulhado em sua própria classe especial. Por exemplo:

class BlackMagic(object):
    def __init__(self):
        self.mydict = {}
        self.__class__ = type(self.__class__.__name__, (self.__class__,), {})
        self.__class__.__contains__ = self.mydict.__contains__

Essencialmente, após o pouco de reatribuição de magia negra self.__class__ para um novo objeto de classe (que se comporta como o anterior, mas tem um ditado vazio e nenhuma outra instância, exceto este self), em qualquer lugar de uma aula de estilo antigo que você atribuiria self.__magicname__, atribuir a self.__class__.__magicname__ em vez staticmethod, não é uma função python normal, a menos que, é claro, em algum caso diferente, você queira que ele receba o self quando chamado na instância).

Aliás, o in operador em uma instância disso BlackMagic aula é mais rápido, por acaso, do que com qualquer uma das soluções previamente propostas - ou pelo menos, então estou medindo com meu confiável habitual -mtimeit (indo diretamente para o built-in method, em vez de seguir rotas de pesquisa normais envolvendo herança e descritores, espanha um pouco da sobrecarga).

Uma metaclasse para automatizar o self.__class__-A ideia de instância não seria difícil de escrever (poderia fazer o trabalho sujo na classe gerada __new__ método, e talvez também defina todos os nomes mágicos para realmente atribuir na classe, se atribuído na instância, seja via __setattr__ ou muitos, muitos propriedades). Mas isso seria justificado apenas se a necessidade desse recurso fosse realmente generalizada (por exemplo, portando um enorme projeto antigo do Python 1.5.2 que usa liberalmente "métodos especiais por instância" para o Python moderno, incluindo o Python 3).

Eu recomendar soluções "inteligentes" ou "magia negra"? Não, eu não: quase invariavelmente é melhor fazer as coisas de maneiras simples e diretas. Mas "quase" é uma palavra importante aqui, e é bom ter "ganchos" tão avançados para as situações raras, mas não inexistentes, em que seu uso pode realmente ser justificado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top