2

Я потратил этот день, пытаясь найти ответ на этот вопрос, но ничего не придумал.Python - Обновление дочерних атрибутов методом базового класса

Предположим, у меня есть несколько классов, каждый из которых содержит методы, идентичные методам в других.

class A: 
    def __init__(self, attr1, attr2, color): 
     self.__attr1 = attr1 
     self.__attr2 = attr2 
     self.__color = color 

    def set_color(self, color): 
     self.__color = color 

class B: 
    def __init__(name, attr3, attr4, color): 
     self.__attr3 = attr3 
     self.__attr4 = attr4 
     self.__color = color 

    def set_color(self, color): 
     self.__color = color 

В этом примере, идентичные методы сводятся к только один идентичный метод, set_color, чтобы проиллюстрировать то, что я пытаюсь сделать.

Есть ли способ устранить повторяющийся код, возможно, с абстрактным классом следующим образом?

class Parent: 
    def set_color(self, color): 
     self.__color = color 

class A(Parent): 
    def __init__(self, attr1, attr2, color): 
     self.__attr1 = attr1 
     self.__attr2 = attr2 
     self.__color = color 


class B(Parent): 
    def __init__(name, attr3, attr4, color): 
     self.__attr3 = attr3 
     self.__attr4 = attr4 
     self.__color = color 

exampleA = A(attr1, attr2, "blue) 

Я хочу, чтобы иметь возможность изменения от синего до красного так, как этот , так что я не должен определять те же методы, в пределах каждого класса A и B

exampleA.set_color("red") 

, но это не работает, как я ожидал, он не меняет значение exampleA.__color

+0

Для получения дополнительной информации см. [Значение одно- и двухзначного символа перед именем объекта в Python] (http://stackoverflow.com/q/1301346/4014959) –

+1

Я понимаю, что это просто пример, но методы setter (и методы getter) не считаются Pythonic, если вы не нуждаетесь в них, чтобы делать «магические» вещи. Если вы просто хотите установить значение атрибута, просто установите его напрямую. –

+1

@ PM2Ring: На самом деле, даже если вы не хотите, чтобы они делали магические вещи, если вам не нужно делать это явным, как часть интерфейса, что волшебство происходит, вам все равно лучше не использовать геттер и сеттер '@ property' ... – abarnert

ответ

4

Вы не можете. Весь смысл атрибутов стиля __private заключается в том, что они частные. Базовые классы, подклассы, аутсайдеры, никто другой не может видеть или изменять их. Если пробует базовый класс или подкласс, они в конечном итоге создадут собственный собственный атрибут на экземпляре, полностью независимом от вашего.

Если вы этого не хотите, просто не используйте атрибуты __private.

Итак, что вам нужно ?

Ну, самая питоническая вещь состоит в том, чтобы просто использовать публичные атрибуты и полностью отказаться от ваших геттеров и сеттеров: exampleA.color = 'red'.

Если у вас есть веская причина, вам нужно скрыть эти атрибуты, возможно, вы захотите сделать их _private вместо __private, что означает, что они конфиденциальны только по соглашению, поэтому ваш код будет работать только как есть. Но опять же, я сомневаюсь, что вам действительно нужно их скрыть.

Если вам действительно нужны __private членов, но все равно действительно нужно победить всю цель __private участников ... ну, в этом случае я лгал; вы на самом деле можете получить к ним доступ, вручную управляя именами. Например, атрибут, названный __color изнутри класса A, называется _A__color за пределами класса A.

Если вам интересно, почему Python позволяет вам нарушать защиту __private ... ну, в отличие от аналогичной функции Java, это не предназначено для защиты вас от чужого вредоносного кода. Из чего он вас защищает, так выглядит сценарий: вы пишете класс A с атрибутом __x. Я пишу класс B с атрибутом __x. Кто-то еще сочиняет наши классы, наследуя от обоих, не сообщая ни вам, ни мне. Мой код все еще работает, так же как и ваш.

Дополнительную информацию см. В разделе урока по private variables и справочной документации по identifiers.

3

Единственная причина, по которой это не будет работать так, как вы, потому что вы используете атрибуты с префиксом __, что делает их «частными» и поэтому недоступными для родительского класса. Не делайте этого: просто используйте имена обычных атрибутов.