Pergunta

Eu tenho uma classe base com uma propriedade que (o método get) que deseja substituir na subclasse. Meu primeiro pensamento foi algo como:

class Foo(object):
    def _get_age(self):
        return 11

    age = property(_get_age)


class Bar(Foo):
    def _get_age(self):
        return 44

Esta não funciona (subclasse bar.age retornos 11). Eu encontrei uma solução com uma expressão lambda que funciona:

age = property(lambda self: self._get_age())

Portanto, esta é a solução certa para o uso de propriedades e substituí-los em uma subclasse, ou há outras maneiras de se fazer isso?

Foi útil?

Solução

Eu simplesmente preferem repetir o property(), assim como você vai repetir o decorador @classmethod ao substituir um método de classe.

Enquanto isso parece muito detalhado, pelo menos para os padrões do Python, você pode observar:

1) para propriedades de apenas de leitura, property pode ser usado como um decorador:

class Foo(object):
    @property
    def age(self):
        return 11

class Bar(Foo):
    @property
    def age(self):
        return 44

2) em Python 2.6, propriedades cresceu um par de métodos setter e deleter que pode ser usado para aplicar a propriedades gerais o atalho já está disponível para aqueles somente leitura:

class C(object):
    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

Outras dicas

Eu não concordo que a resposta escolhida é a maneira ideal para permitir substituindo os métodos de propriedade. Se você espera que os getters e setters para ser substituído, então você pode usar lambda para fornecer acesso à auto, com algo como lambda self: self.<property func>.

Isso funciona (pelo menos) para versões do Python 2,4-3,6.

Se alguém sabe uma maneira de fazer isso com usando a propriedade como um decorador em vez de como uma chamada de propriedade direta (), eu gostaria de ouvi-lo!

Exemplo:

class Foo(object):
    def _get_meow(self):
        return self._meow + ' from a Foo'
    def _set_meow(self, value):
        self._meow = value
    meow = property(fget=lambda self: self._get_meow(),
                    fset=lambda self, value: self._set_meow(value))

Desta forma, uma substituição pode ser facilmente executadas:

class Bar(Foo):
    def _get_meow(self):
        return super(Bar, self)._get_meow() + ', altered by a Bar'

de modo que:

>>> foo = Foo()
>>> bar = Bar()
>>> foo.meow, bar.meow = "meow", "meow"
>>> foo.meow
"meow from a Foo"
>>> bar.meow
"meow from a Foo, altered by a Bar"

Eu descobri isso em Geek em jogo .

Outra maneira de fazê-lo, sem ter que criar todas as classes adicionais. Eu adicionei um método set para mostrar o que você faria se você só substituir um dos dois:

class Foo(object):
    def _get_age(self):
        return 11

    def _set_age(self, age):
        self._age = age

    age = property(_get_age, _set_age)


class Bar(Foo):
    def _get_age(self):
        return 44

    age = property(_get_age, Foo._set_age)

Este é um exemplo muito artificial, mas você deve ficar com a ideia.

Sim, esta é a maneira de fazê-lo; executa a declaração de propriedade no momento da classe definição pai é executado, o que significa que só pode 'ver' as versões dos métodos que existem na classe pai. Então, quando você redefinir um ou mais desses métodos em uma classe filha, você precisa re-declarar a propriedade usando a versão classe criança do método (s).

Eu concordo com a sua solução, que parece um método de modelo on-the-fly. este artigo lida com seu problema e fornece exatamente a sua solução.

Algo como isso vai funcionar

class HackedProperty(object):
    def __init__(self, f):
        self.f = f
    def __get__(self, inst, owner):    
        return getattr(inst, self.f.__name__)()

class Foo(object):
    def _get_age(self):
        return 11
    age = HackedProperty(_get_age)

class Bar(Foo):
    def _get_age(self):
        return 44

print Bar().age
print Foo().age

O mesmo que @ mr-b 's, mas com decorador.

class Foo(object):
    def _get_meow(self):
        return self._meow + ' from a Foo'
    def _set_meow(self, value):
        self._meow = value
    @property
    def meow(self):
        return self._get_meow()
    @meow.setter
    def meow(self, value):
        self._set_meow(value)

Desta forma, uma substituição pode ser facilmente executadas:

class Bar(Foo):
    def _get_meow(self):
        return super(Bar, self)._get_meow() + ', altered by a Bar'

Eu corri para problemas de configuração uma propriedade em uma classe pai de uma classe criança. A seguir workround estende uma propriedade de um dos pais, mas faz isso chamando o método _set_age do pai diretamente. Enrugada deve ser sempre correto. É um pouco embora javathonic.

import threading


class Foo(object):
    def __init__(self):
        self._age = 0

    def _get_age(self):
        return self._age

    def _set_age(self, age):
        self._age = age

    age = property(_get_age, _set_age)


class ThreadsafeFoo(Foo):

    def __init__(self):
        super(ThreadsafeFoo, self).__init__()
        self.__lock = threading.Lock()
        self.wrinkled = False

    def _get_age(self):
        with self.__lock:
             return super(ThreadsafeFoo, self).age

    def _set_age(self, value):
        with self.__lock:
            self.wrinkled = True if value > 40 else False
            super(ThreadsafeFoo, self)._set_age(value)

    age = property(_get_age, _set_age)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top