Подтвердить что ты не робот

Когда я должен использовать классы в Python?

Я программировал на python около двух лет; в основном материал данных (pandas, mpl, numpy), но также сценарии автоматизации и небольшие веб-приложения. Я пытаюсь стать лучшим программистом и увеличить свои знания на питоне, и одна из вещей, которая меня беспокоит, заключается в том, что я никогда не использовал класс (кроме копирования случайных флагов для небольших веб-приложений). Я вообще понимаю, что это такое, но я не могу склонить голову, почему я нуждаюсь в них над простой функцией.

Чтобы добавить специфика к моему вопросу: я пишу много автоматических отчетов, которые всегда включают в себя извлечение данных из нескольких источников данных (mongo, sql, postgres, apis), многое или небольшое перетаскивание и форматирование данных, запись данных в csv/excel/html, отправьте его по электронной почте. Скрипты варьируются от ~ 250 строк до ~ 600 строк. Будет ли у меня какая-то причина использовать классы для этого и почему?

4b9b3361

Ответ 1

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

Во-первых, отказ от ответственности: ООП частично противоречит "Функциональное программирование" , которое представляет собой другую парадигму, используемую в Python. Не все, кто программирует на Python (или, конечно же, большинство языков), используют OOP. Вы можете многое сделать в Java 8, который не очень объектно ориентирован. Если вы не хотите использовать ООП, не делайте этого. Если вы просто пишете одноразовые скрипты для обработки данных, которые больше никогда не будете использовать, продолжайте писать так, как вы.

Однако существует много причин использовать ООП.

Некоторые причины:

  • Организация: ООП определяет хорошо известные и стандартные способы описания и определения как данных, так и процедуры в коде. Как данные, так и процедура могут храниться на разных уровнях определения (в разных классах), и есть стандартные способы говорить об этих определениях. То есть, если вы используете ООП стандартным образом, это поможет вашему более позднему я и другим понять, отредактировать и использовать ваш код. Кроме того, вместо использования сложного, произвольного механизма хранения данных (dicts dicts или списков или dicts или списков dicts наборов или что-то еще) вы можете называть части структур данных и удобно ссылаться на них.

  • Состояние: ООП помогает вам определять и отслеживать состояние. Например, в классическом примере, если вы создаете программу, которая обрабатывает студентов (например, программу оценки), вы можете хранить всю необходимую информацию о них в одном месте (имя, возраст, пол, уровень оценки, курсы, классы, учителя, сверстники, диеты, особые потребности и т.д.), и эти данные сохраняются до тех пор, пока объект жив, и легко доступны.

  • Encapsulation: При инкапсуляции процедура и данные сохраняются вместе. Методы (термин ООП для функций) определяются непосредственно рядом с данными, которые они работают и производят. На языке, подобном Java, который позволяет контроль доступа или на Python, в зависимости от того, как вы описываете свой публичный API, это означает, что методы и данные могут быть скрыты от пользователя. Это означает, что если вам нужно или хотите изменить код, вы можете делать все, что хотите для реализации кода, но сохраняйте общедоступные API-интерфейсы одинаковыми.

  • Inheritance: Наследование позволяет определить данные и процедуру в одном месте (в одном классе), а затем переопределить или расширить эту функциональность позже. Например, в Python я часто вижу, как люди создают подклассы класса dict, чтобы добавить дополнительные функции. Общее изменение переопределяет метод, который генерирует исключение, когда запрашивается ключ из словаря, который не существует, чтобы дать значение по умолчанию на основе неизвестного ключа. Это позволяет вам расширить свой собственный код сейчас или позже, позволить другим расширять ваш код и позволяет расширять код других людей.

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

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

Пример примера использования студента (нет гарантии качества кода, всего лишь пример):

Объектно-ориентированный

class Student(object):
    def __init__(self, name, age, gender, level, grades=None):
        self.name = name
        self.age = age
        self.gender = gender
        self.level = level
        self.grades = grades or {}

    def setGrade(self, course, grade):
        self.grades[course] = grade

    def getGrade(self, course):
        return self.grades[course]

    def getGPA(self):
        return sum(self.grades.values())/len(self.grades)

# Define some students
john = Student("John", 12, "male", 6, {"math":3.3})
jane = Student("Jane", 12, "female", 6, {"math":3.5})

# Now we can get to the grades easily
print(john.getGPA())
print(jane.getGPA())

Стандартный Dict

def calculateGPA(gradeDict):
    return sum(gradeDict.values())/len(gradeDict)

students = {}
# We can set the keys to variables so we might minimize typos
name, age, gender, level, grades = "name", "age", "gender", "level", "grades"
john, jane = "john", "jane"
math = "math"
students[john] = {}
students[john][age] = 12
students[john][gender] = "male"
students[john][level] = 6
students[john][grades] = {math:3.3}

students[jane] = {}
students[jane][age] = 12
students[jane][gender] = "female"
students[jane][level] = 6
students[jane][grades] = {math:3.5}

# At this point, we need to remember who the students are and where the grades are stored. Not a huge deal, but avoided by OOP.
print(calculateGPA(students[john][grades]))
print(calculateGPA(students[jane][grades]))

Ответ 2

Всякий раз, когда вам нужно поддерживать состояние своих функций, оно не может быть выполнено с помощью генераторов (функции, которые дают, а не возврат). Генераторы сохраняют свое собственное состояние.

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

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

Если вы хотите написать "pythonic" код, вы должны предпочесть контекстные менеджеры и генераторы над классами. Это будет чище.

Если вы хотите расширить функциональность, вы почти всегда сможете выполнить ее сдерживанием, а не наследованием.

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

Если вам нужен деструктор стиля С++ (RIIA), вы определенно НЕ хотите использовать классы. Вы хотите, чтобы контекстные менеджеры.

Ответ 3

Я думаю, вы все сделаете правильно. Классы разумны, когда вам нужно моделировать некоторую бизнес-логику или сложные жизненные процессы с трудными отношениями. В качестве примера:

  • Несколько функций с общим состоянием
  • Более одной копии тех же переменных состояния
  • Чтобы расширить поведение существующей функциональности

Я также предлагаю вам смотреть это классическое видео

Ответ 4

Класс определяет объект реального мира. Если вы работаете над тем, что существует индивидуально и имеет свою собственную логику, которая отделена от других, вы должны создать для нее класс. Например, класс, который инкапсулирует подключение к базе данных.

Если это не так, не нужно создавать класс