Какой смысл наследования в Python?

Определенно Docker для победы!

Как вы, возможно, знаете, Vagrant предназначен для управления виртуальными машинами, а Docker - для управления программными контейнерами. Если вы не знаете о разнице, вот что: Контейнер программного обеспечения может использовать тот же компьютер и ядро ​​совместно с другими контейнерами программного обеспечения. Используя контейнеры, вы экономите деньги, потому что вы не тратите ресурсы на несколько операционных систем (ядер), вы можете упаковать больше программного обеспечения на сервер, сохраняя хорошую степень изоляции.

Конечно, это новая дисциплина, чтобы заботиться о своих собственных питалах и проблемах.

Выберите Docker Swarm, если ваши требования превышают лимит ресурсов одной машины.

80
задан bignose 1 January 2016 в 02:16
поделиться

10 ответов

Вы имеете в виду утиную типизацию во время выполнения как "переопределяющее" наследование, однако я считаю, что у наследования есть свои достоинства как подход к проектированию и реализации, поскольку он является неотъемлемой частью объектно-ориентированного проектирования. . По моему скромному мнению, вопрос о том, сможете ли вы добиться чего-то в противном случае, не очень актуален, потому что на самом деле вы можете кодировать Python без классов, функций и прочего, но вопрос в том, насколько хорошо продуманным, надежным и читаемым будет ваш код.

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

Во-первых, если вы кодируете с умом, ваша функция makeSpeak может захотеть проверить, что ее ввод действительно является Animal, а не только то, что «он может говорить», и в этом случае наиболее элегантным методом будет использование наследования. Очередной раз, вы можете сделать это другими способами, но в этом прелесть объектно-ориентированного дизайна с наследованием - ваш код «действительно» проверит, является ли ввод «животным».

Во-вторых, и это явно более прямолинейно, это инкапсуляция - еще один неотъемлемый элемент часть объектно-ориентированного дизайна. Это становится актуальным, когда у предка есть элементы данных и / или неабстрактные методы. Возьмем следующий глупый пример, в котором у предка есть функция (speak_twice), которая вызывает тогда абстрактную функцию:

class Animal(object):
    def speak(self):
        raise NotImplementedError()

    def speak_twice(self):
        self.speak()
        self.speak()

class Dog(Animal):
    def speak(self):
        print "woff!"

class Cat(Animal):
    def speak(self):
        print "meow"

Предполагая, что "speak_twice" является важной функцией, вы не хотите ее кодировать как в собаках, так и в кошках, и я уверен, что вы сможете экстраполировать этот пример. Конечно, вы могли бы реализовать автономную функцию Python, которая будет принимать какой-нибудь объект типа «утка», проверять, есть ли у него функция разговора, и вызывать ее дважды, но это одновременно не элегантно и пропускает пункт номер 1 (подтвердите, что это животное). Хуже того, и чтобы усилить пример инкапсуляции, что, если функция-член в классе-потомке захотела использовать "speak_twice" ?

Это становится еще яснее, если класс-предок имеет член данных, например «number_of_legs» , который используется неабстрактными методами в предке, например «print_number_of_legs» , но инициируется в конструкторе класса-потомка (например, Dog инициализирует его с помощью 4, тогда как Snake инициализирует его 0).

Опять же, я уверен, что существует бесконечное количество примеров, но в основном каждое (достаточно большое) программное обеспечение, основанное на твердом объектно-ориентированном дизайне, потребует наследования.

s одновременно неэлегантно и пропускает пункт номер 1 (подтвердите, что это животное). Хуже того, и чтобы усилить пример инкапсуляции, что, если функция-член в классе-потомке захотела использовать "speak_twice" ?

Это становится еще яснее, если класс-предок имеет член данных, например «number_of_legs» , который используется неабстрактными методами в предке, например «print_number_of_legs» , но инициируется в конструкторе класса-потомка (например, Dog инициализирует его с помощью 4, тогда как Snake инициализирует его 0).

Опять же, я уверен, что существует бесконечное количество примеров, но в основном каждое (достаточно большое) программное обеспечение, основанное на твердом объектно-ориентированном дизайне, потребует наследования.

s одновременно неэлегантно и пропускает пункт номер 1 (подтвердите, что это животное). Хуже того, и чтобы усилить пример инкапсуляции, что, если функция-член в классе-потомке захотела использовать "speak_twice" ?

Это становится еще яснее, если класс-предок имеет член данных, например «number_of_legs» , который используется неабстрактными методами в предке, например «print_number_of_legs» , но инициируется в конструкторе класса-потомка (например, Dog инициализирует его с помощью 4, тогда как Snake инициализирует его 0).

Опять же, я уверен, что существует бесконечное количество примеров, но в основном каждое (достаточно большое) программное обеспечение, основанное на твердом объектно-ориентированном дизайне, потребует наследования.

и, чтобы усилить пример инкапсуляции, что, если бы функция-член в классе-потомке захотела использовать «speak_twice» ?

Это станет еще яснее, если класс-предок имеет член-данные, например "number_of_legs" , который используется неабстрактными методами в предке, например "print_number_of_legs" , но инициируется в конструкторе класса-потомка (например, Dog инициализирует его с помощью 4, тогда как Snake инициализирует его с 0).

Опять же, я уверен, что существует бесконечное количество примеров, но в основном каждое (достаточно большое) программное обеспечение, основанное на твердом объектно-ориентированном дизайне, потребует наследования.

и для усиления примера инкапсуляции: что, если функция-член в классе-потомке захотела использовать "speak_twice" ?

Это станет еще яснее, если класс-предок имеет член-данные, например "number_of_legs" , который используется неабстрактными методами в предке, например «print_number_of_legs» , но инициируется в конструкторе класса-потомка (например, Dog инициализирует его с помощью 4, тогда как Snake инициализирует его с 0).

Опять же, я уверен, что существует бесконечное количество примеров, но в основном каждое (достаточно большое) программное обеспечение, основанное на твердом объектно-ориентированном дизайне, потребует наследования.

?

Это становится еще яснее, если класс-предок имеет член данных, например «number_of_legs» , который используется неабстрактными методами в предке, например «print_number_of_legs» , но инициируется в конструкторе класса-потомка (например, Dog инициализирует его значением 4, а Snake инициализирует его значением 0).

Опять же, я уверен, что существует бесконечное количество примеров, но в основном каждое (достаточно большое) программное обеспечение, основанное на твердом объектно-ориентированном дизайне, потребует наследования.

?

Это становится еще яснее, если класс-предок имеет член данных, например «number_of_legs» , который используется неабстрактными методами в предке, например «print_number_of_legs» , но инициируется в конструкторе класса-потомка (например, Dog инициализирует его значением 4, а Snake инициализирует его значением 0).

Опять же, я уверен, что существует бесконечное количество примеров, но в основном каждое (достаточно большое) программное обеспечение, основанное на твердом объектно-ориентированном дизайне, потребует наследования.

Dog инициализирует его с помощью 4, а Snake инициализирует его с помощью 0).

Опять же, я уверен, что существует бесконечное количество примеров, но в основном каждое (достаточно большое) программное обеспечение, основанное на твердом объектно-ориентированном дизайне, потребует наследования.

Dog инициализирует его с помощью 4, а Snake инициализирует его с помощью 0).

Опять же, я уверен, что существует бесконечное количество примеров, но в основном каждое (достаточно большое) программное обеспечение, основанное на твердом объектно-ориентированном дизайне, потребует наследования.

78
ответ дан 24 November 2019 в 09:58
поделиться

Наследование в Python - это повторное использование кода. Факторизуйте общие функции в базовом классе и реализуйте различные функции в производных классах.

12
ответ дан 24 November 2019 в 09:58
поделиться

Наследование в Python удобнее, чем что-либо еще. Я считаю, что лучше всего использовать его, чтобы предоставить классу «поведение по умолчанию»

. Действительно, существует значительное сообщество разработчиков Python, которые вообще выступают против использования наследования. Что бы вы ни делали, не переусердствуйте. Слишком сложная иерархия классов - верный способ получить ярлык «Java-программиста», а у вас просто не может быть этого. : -)

10
ответ дан 24 November 2019 в 09:58
поделиться

Я думаю, что суть наследования в Python заключается не в том, чтобы компилировать код, а в реальной причине наследования, которое расширяет класс в другой дочерний класс и переопределяет логику в базовый класс. Однако «утка» в Python делает концепцию «интерфейса» бесполезной, потому что вы можете просто проверить, существует ли метод перед вызовом, без необходимости использовать интерфейс для ограничения структуры классов.

8
ответ дан 24 November 2019 в 09:58
поделиться

Классы в Python - это в основном просто способы группировки множества функций и данных. Они отличаются от классов в C ++ и т. Д.

В основном я видел наследование, используемое для переопределения методы суперкласса. Например, возможно более питонское использование наследования было бы ...

from world.animals import Dog

class Cat(Dog):
    def speak(self):
        print "meow"

Конечно, кошки не относятся к типу собак, но у меня есть этот (сторонний) Dog класс, который отлично работает, кроме метода speak , который я хочу переопределить - это избавляет от повторной реализации всего класса, так что он мяукает. Опять же, хотя Кот не является типом Собаки , но кошка наследует множество атрибутов ..

Намного лучший (практический) пример переопределения метода или Атрибут - это то, как вы меняете пользовательский агент для urllib. Вы в основном подклассифицируете urllib.FancyURLopener и меняете атрибут версии ( из документации ):

import urllib

class AppURLopener(urllib.FancyURLopener):
    version = "App/1.7"

urllib._urlopener = AppURLopener()

Другой способ использования исключений - для Исключений, когда наследование используется в более "правильном" "way:

class AnimalError(Exception):
    pass

class AnimalBrokenLegError(AnimalError):
    pass

class AnimalSickError(AnimalError):
    pass

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

0
ответ дан 24 November 2019 в 09:58
поделиться

В C ++ / Java / и т. Д. Полиморфизм вызывается наследованием. Откажитесь от этого заблуждающегося убеждения, и динамические языки откроются вам.

По сути, в Python нет столько интерфейса, сколько «понимания того, что определенные методы являются вызываемыми». Довольно волнистые и академически звучащие, не так ли? Это означает, что, поскольку вы вызываете "говорить", вы явно ожидаете, что у объекта должен быть метод "говорить". Просто, а? Это очень по-лисковски в том смысле, что пользователи класса определяют его интерфейс, хорошая концепция дизайна, которая приводит вас к более здоровому TDD.

Итак, что осталось, как вежливо удалось избежать другого автора, уловка совместного использования кода . Вы можете записать одно и то же поведение в каждый «дочерний» класс, но это будет лишним. Легче наследовать или смешивать функциональность, неизменную в иерархии наследования. Меньший, DRY-код в целом лучше.

5
ответ дан 24 November 2019 в 09:58
поделиться

Я думаю, что очень сложно дать осмысленный, конкретный ответ с такими абстрактными примерами ...

Для упрощения, существует два типа наследования: интерфейс и реализация. Если вам нужно унаследовать реализацию, тогда python не так уж отличается от статически типизированных объектно-ориентированных языков, таких как C ++.

Наследование интерфейса - это то место, где есть большая разница, с фундаментальными последствиями для дизайна вашего программного обеспечения, по моему опыту. Такие языки, как Python, не заставляют вас использовать наследование в этом случае, и в большинстве случаев полезно избегать наследования, потому что позже очень сложно исправить неправильный выбор дизайна. Это хорошо известный вопрос, который поднимается в любой хорошей книге по ООП.

Бывают случаи, когда в Python рекомендуется использовать наследование для интерфейсов, например, для подключаемых модулей и т. Д. Для этих случаев в Python 2.5 и ниже отсутствует «встроенный» элегантный подход, и несколько крупных фреймворков разработали свои собственные решения (zope, trac, twister). Python 2.6 и выше имеет классы ABC для решения этой .

7
ответ дан 24 November 2019 в 09:58
поделиться

Вы можете обойти наследование в Python и почти на любом другом языке. Однако все дело в повторном использовании кода и упрощении кода.

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

Допустим, у вас есть d, который является собакой, которая является подклассом Animal.

command = raw_input("What do you want the dog to do?")
if command in dir(d): getattr(d,command)()

Если все, что ввел пользователь, доступно, код запустит правильный метод.

Используя это, вы можете создать любую комбинацию гибридного чудовища Млекопитающее / Рептилия / Птица, какую захотите, и теперь вы можете заставить его говорить «Кора!» во время полета и высунув свой раздвоенный язык, и он справится с этим правильно! Удачи!

1
ответ дан 24 November 2019 в 09:58
поделиться

Я не вижу особого смысла в наследовании.

Каждый раз, когда я когда-либо использовал наследование в реальных системах, я горел, потому что это приводило к запутанной сети зависимостей, или я просто со временем понял, что без него мне было бы намного лучше. Теперь я избегаю этого по мере возможности. Мне это просто никогда не пригодилось.

class Repeat:
    "Send a message more than once"
    def __init__(repeat, times, do):
        repeat.times = times
        repeat.do = do

    def __call__(repeat):
        for i in xrange(repeat.times):
             repeat.do()

class Speak:
    def __init__(speak, animal):
        """
        Check that the animal can speak.

        If not we can do something about it (e.g. ignore it).
        """
        speak.__call__ = animal.speak

    def twice(speak):
        Repeat(2, speak)()

class Dog:
     def speak(dog):
         print "Woof"

class Cat:
     def speak(cat):
         print "Meow"

>>> felix = Cat()
>>> Speak(felix)()
Meow

>>> fido = Dog()
>>> speak = Speak(fido)
>>> speak()
Woof

>>> speak.twice()
Woof

>>> speak_twice = Repeat(2, Speak(felix))
>>> speak_twice()
Meow
Meow

Джеймсу Гослингу однажды задали на пресс-конференции вопрос примерно следующего содержания: «Если бы вы могли вернуться назад и заняться Java по-другому, что бы вы оставили?». Его ответ был «Классы», над которыми был смех. Однако он был серьезен и объяснил, что на самом деле проблема заключалась не в классах, а в наследовании.

Я в некотором роде рассматриваю это как зависимость от наркотиков - это дает вам быстрое решение, которое кажется хорошим, но, в конце концов, это сбивает вас с толку. Под этим я подразумеваю, что это удобный способ повторного использования кода, но он вызывает нездоровую связь между дочерним и родительским классами. Изменения родителя могут сломать ребенка. Дочерний элемент зависит от родителя в отношении определенных функций и не может изменять эти функции. Следовательно, функциональность, предоставляемая дочерним элементом, также связана с родительским - вы можете иметь только оба.

Лучше предоставить один единственный клиентский класс для интерфейса, который реализует интерфейс, используя функциональность других объектов, которые составлены в время строительства. Делая это через правильно спроектированные интерфейсы, можно исключить все связи, и мы предоставляем легко компонуемый API (в этом нет ничего нового - большинство программистов уже это делают, но этого недостаточно). Обратите внимание, что реализующий класс не должен просто предоставлять функциональность, в противном случае клиент должен просто использовать составленные классы напрямую - он должен сделать что-то новое, объединив эти функции.

Есть аргумент из лагеря наследования, что реализации чистого делегирования страдают, потому что они требуют большого количества клея. 'методы, которые просто передают значения через' цепочку 'делегирования. Однако это просто переосмысление конструкции, похожей на наследование, с использованием делегирования. Программисты, которые слишком много лет знакомы с проектами, основанными на наследовании, особенно уязвимы для попадания в эту ловушку, поскольку, сами того не осознавая, они будут думать о том, как бы реализовать что-то с помощью наследования, а затем преобразовать это в делегирование.

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

  • Наследование создает классы, которые больше чем одно, потому что они перепутались с родительскими классами.

  • Таким образом, использование наследования делает классы, которые трудно использовать повторно.

  • 1
    ответ дан 24 November 2019 в 09:58
    поделиться

    Утиная типизация делает бессмысленным не наследование, а интерфейсы - вроде того, который вы выбрали при создании полностью абстрактного класса животных.

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

    Поскольку Python может напрямую знать возможности любого объекта, и поскольку эти возможности изменяются за пределами определения класса, идея Использование чисто абстрактного интерфейса для «указания» программе, какие методы могут быть вызваны, в некоторой степени бессмысленно. Но это не единственный и даже не главный пункт наследования.

    5
    ответ дан 24 November 2019 в 09:58
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: