파이썬에서 언제 클래스를 사용해야합니까?


177

저는 약 2 년 동안 파이썬으로 프로그래밍 해 왔습니다. 주로 데이터 (팬더, mpl, numpy)뿐만 아니라 자동화 스크립트 및 소규모 웹 앱도 있습니다. 나는 더 나은 프로그래머가되고 파이썬 지식과 나를 귀찮게하는 것 중 하나를 배우려고 노력하고있다. 나는 일반적으로 그들이 무엇인지 이해하지만 간단한 기능을 통해 왜 그것들을 필요로하는지 머리를 감쌀 수는 없습니다.

내 질문에 특이성을 더하기 위해 : 나는 항상 여러 데이터 소스 (mongo, sql, postgres, apis)에서 데이터를 가져 오거나 많은 데이터 소거 및 서식을 수행하고 csv / excel에 데이터를 쓰는 수많은 자동화 된 보고서를 작성합니다. / html, 이메일로 보내십시오. 스크립트 범위는 ~ 250 줄 ~ ~ 600 줄입니다. 클래스를 사용하여이를 수행하는 이유와 이유가 있습니까?


15
코드를 더 잘 관리 할 수 ​​있다면 클래스없이 코딩하는 데 아무런 문제가 없습니다. OOP 프로그래머는 언어 디자인의 제약이나 다른 패턴의 피상적 이해로 인해 문제를 과장하는 경향이 있습니다.
Jason Hu

답변:


133

클래스는 객체 지향 프로그래밍 의 기둥입니다 . OOP는 코드 구성, 재사용 성 및 캡슐화에 크게 관심이 있습니다.

첫째, 면책 조항 : OOP는 부분적으로 파이썬에서 많이 사용되는 다른 패러다임 인 Functional Programming 과 대조됩니다 . 파이썬 (또는 대부분의 언어)으로 프로그래밍하는 모든 사람이 OOP를 사용하는 것은 아닙니다. Java 8에서는 객체 지향적이지 않은 많은 작업을 수행 할 수 있습니다. OOP를 사용하지 않으려면 사용하지 마십시오. 다시는 사용하지 않을 데이터를 처리하기 위해 일회용 스크립트를 작성하는 경우에는 그대로 사용하십시오.

그러나 OOP를 사용해야하는 많은 이유가 있습니다.

몇 가지 이유 :

  • 조직 : OOP는 코드에서 데이터와 프로 시저를 모두 설명하고 정의하는 잘 알려진 표준 방법을 정의합니다. 데이터와 프로시 저는 다양한 수준의 정의 (다른 클래스로)로 저장 될 수 있으며 이러한 정의에 대해 이야기하는 표준 방법이 있습니다. 즉, 표준 방식으로 OOP를 사용하면 나중에 자신과 다른 사람이 코드를 이해하고 편집하고 사용하는 데 도움이됩니다. 또한 복잡한 임의의 데이터 저장 메커니즘 (dicts 또는 list 또는 dicts 또는 set of dicts 등의 목록 등)을 사용하는 대신 데이터 구조의 이름을 지정하고 편리하게 참조 할 수 있습니다.

  • 상태 : OOP는 상태를 정의하고 추적하는 데 도움이됩니다. 예를 들어, 전형적인 예에서 학생을 처리하는 프로그램 (예 : 학년 프로그램)을 작성하는 경우 필요한 모든 정보를 이름, 나이, 성별, 학년, 코스, 성적, 교사, 동료,식이 요법, 특별 요구 사항 등),이 데이터는 개체가 살아있는 한 지속되며 쉽게 액세스 할 수 있습니다.

  • 캡슐화 : 캡슐화를 통해 프로 시저와 데이터가 함께 저장됩니다. 방법 (함수에 대한 OOP 용어)은 작동하고 생성하는 데이터와 함께 정의됩니다. 액세스 제어 를 허용하는 Java와 같은 언어 또는 Python에서는 공용 API를 설명하는 방법에 따라 메소드와 데이터를 사용자에게 숨길 수 있습니다. 이것이 의미하는 바는 코드를 필요로하거나 변경하려는 경우 코드 구현에 원하는 모든 작업을 수행 할 수 있지만 공개 API는 동일하게 유지한다는 것입니다.

  • 상속 : 상속을 사용하면 한 곳에서 (한 클래스에서) 데이터와 프로 시저를 정의한 다음 나중에 해당 기능을 재정의하거나 확장 할 수 있습니다. 예를 들어, 파이썬에서는 dict추가 기능을 추가하기 위해 클래스의 하위 클래스를 만드는 사람들이 종종 있습니다 . 일반적인 변경은 알 수없는 키를 기반으로 기본값을 제공하기 위해 존재하지 않는 사전에서 키를 요청할 때 예외를 발생시키는 메소드를 대체하는 것입니다. 이를 통해 지금 또는 나중에 자신의 코드를 확장하고, 다른 사람들이 귀하의 코드를 확장하고, 다른 사람들의 코드를 확장 할 수 있습니다.

  • 재사용 성 : 이러한 모든 이유 및 기타 이유로 인해 코드의 재사용 성이 향상됩니다. 객체 지향 코드를 사용하면 견고한 (테스트 된) 코드를 한 번 작성한 다음 반복해서 재사용 할 수 있습니다. 특정 사용 사례에 맞게 무언가를 조정해야하는 경우 기존 클래스에서 상속하고 기존 동작을 덮어 쓸 수 있습니다. 무언가를 변경해야 할 경우 기존의 공개 메소드 서명을 유지하면서 모든 것을 변경할 수 있으며 아무도 현명하지 않습니다.

다시 말하지만 OOP를 사용하지 않는 몇 가지 이유가 있으며 필요하지 않습니다. 그러나 운 좋게 파이썬과 같은 언어를 사용하면 약간 또는 많이 사용할 수 있습니다.

학생 유스 케이스의 예 (코드 품질에 대한 보장은 아니며 단지 예) :

객체 지향

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())

표준 딕트

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]))

"수율"때문에 파이썬 캡슐화는 클래스보다 생성자와 컨텍스트 관리자에서 더 깨끗합니다.
Dmitry Rubanovich

4
@meter 예를 추가했습니다. 도움이 되길 바랍니다. 여기서 주목할 점은 올바른 이름을 가진 dicts의 키에 의존하지 않고 Python 인터프리터는 정의 된 필드를 정의하지 않은 경우 (정의 된 필드는 아니지만 (Java 및 기타)) OOP 언어를 사용하면 Python과 같은 클래스 외부의 필드를 정의 할 수 없습니다)).
dantiston

5
@meter도 캡슐화의 예입니다. 오늘이 구현은 괜찮습니다. 한 번만 대학에서 50,000 명의 학생들에게 GPA를 가져 오기만하면되기 때문입니다. 이제 내일 우리는 보조금을 받고 매 초마다 모든 학생의 현재 GPA를 제공해야합니다 (물론 아무도 요구하지는 않지만 계산 상 어려움을 겪고 있습니다). 그런 다음 GPA를 "메모"하고 GPA가 변경 될 때만 계산할 수 있습니다 (예 : setGrade 메소드에서 변수를 설정하여). 사용자는 여전히 getGPA ()를 사용하지만 구현이 변경되었습니다.
dantiston

4
@dantiston,이 예제에는 collections.namedtuple이 필요합니다. 새로운 유형의 Student = collections.namedtuple ( "학생", "이름, 나이, 성별, 레벨, 성적")을 만들 수 있습니다. 그런 다음 john = Student ( "John", 12, "male", grades = { 'math': 3.5}, level = 6) 인스턴스를 만들 수 있습니다. 클래스를 만들 때와 마찬가지로 위치 인수와 명명 된 인수를 모두 사용합니다. 이것은 파이썬에서 이미 구현 된 데이터 유형입니다. 그런 다음 john [0] 또는 john.name을 참조하여 튜플의 첫 번째 요소를 가져올 수 있습니다. john의 등급을 john.grades.values ​​()로 얻을 수 있습니다. 그리고 그것은 이미 당신을 위해 완료되었습니다.
Dmitry Rubanovich

2
나를 위해 캡슐화는 항상 OOP를 사용하는 충분한 이유입니다. 합리적인 규모의 코딩 프로젝트에 가치가 OOP를 사용하지 않는 것을 보려고 노력합니다. 나는 반대의 질문에 대한 답이 필요하다고 생각한다 :)
San Jay

23

함수의 상태를 유지해야 할 때마다 생성기 (복귀하지 않고 생성되는 함수)로는 수행 할 수 없습니다. 발전기는 자체 상태를 유지합니다.

표준 연산자 를 재정의 하려면 클래스가 필요합니다.

방문자 패턴을 사용할 때마다 수업이 필요합니다. 다른 모든 디자인 패턴은 생성기, 컨텍스트 관리자 (클래스보다 생성기로 더 잘 구현 됨) 및 POD 유형 (사전, 목록 및 튜플 등)을 사용하여보다 효과적이고 깨끗하게 달성 할 수 있습니다.

"pythonic"코드를 작성하려면 클래스보다 컨텍스트 관리자 및 생성기를 선호해야합니다. 깨끗합니다.

기능을 확장하려는 경우 거의 항상 상속이 아닌 격리로 기능을 수행 할 수 있습니다.

모든 규칙에 따라 예외가 있습니다. 기능을 빠르게 캡슐화하려면 (즉, 라이브러리 수준 재사용 가능 코드 대신 테스트 코드 작성) 상태를 클래스에 캡슐화 할 수 있습니다. 간단하고 재사용 할 필요가 없습니다.

C ++ 스타일 소멸자 (RIIA)가 필요한 경우 클래스를 사용하고 싶지 않습니다. 컨텍스트 관리자가 필요합니다.


1
@DmitryRubanovich 클로저는 Python의 생성기를 통해 구현되지 않습니다.
Eli Korvigo

1
@DmitryRubanovich 나는 "폐쇄는 파이썬에서 생성기로 구현된다"고 언급했지만 사실이 아닙니다. 마감이 훨씬 유연합니다. 생성기는 Generator인스턴스 (특수 반복자) 를 반환 해야하지만 클로저는 서명을 가질 수 있습니다. 클로저를 만들어 기본적으로 대부분의 클래스를 피할 수 있습니다. 그리고 클로저는 단순히 "다른 기능의 맥락에서 정의 된 기능"이 아닙니다.
Eli Korvigo

3
@Eli Korvigo는 사실, 제너레이터는 구문 적으로 큰 도약입니다. 함수가 스택의 추상화와 같은 방식으로 큐의 추상화를 작성합니다. 그리고 대부분의 데이터 흐름은 스택 / 큐 프리미티브에서 함께 구성 될 수 있습니다.
Dmitry Rubanovich가

1
@DmitryRubanovich 우리는 사과와 오렌지를 이야기하고 있습니다. 저는 제너레이터가 매우 제한된 수의 경우에 유용하며 범용 스테이트 풀 콜 러블의 대체물로 간주 될 수 없다고 말합니다. 당신은 내 요점을 모순하지 않고 그들이 얼마나 위대한 지 말해주었습니다.
Eli Korvigo

1
@ Elli Korvigo, 그리고 callables는 함수의 일반화 일뿐입니다. 스택 자체에 대한 구문 설탕입니다. 생성기는 대기열 처리에 대한 구문 설탕입니다. 그러나 구문이 개선되어보다 복잡한 구문을보다 쉽고 명확하게 구축 할 수 있습니다. '.next ()'는 거의 사용되지 않습니다 (btw).
Dmitry Rubanovich

11

나는 당신이 그것을 올바르게 생각합니다. 어려운 비즈니스 관계 또는 어려운 실제 프로세스를 시뮬레이션해야하는 경우 클래스는 합리적입니다. 예를 들어 :

  • 공유 상태를 가진 여러 기능
  • 동일한 상태 변수의 둘 이상의 사본
  • 기존 기능의 동작을 확장하려면

또한 이 클래식 비디오 를 시청할 것을 제안합니다


3
콜백 함수가 파이썬에서 영속 상태를 필요로 할 때 클래스를 사용할 필요가 없습니다. return 대신 Python의 yield를 사용하면 함수가 다시 입력됩니다.
Dmitry Rubanovich

4

클래스는 실제 개체를 정의합니다. 개별적으로 존재하고 다른 논리와 분리 된 자체 논리가있는 작업을 수행하는 경우이를위한 클래스를 작성해야합니다. 예를 들어 데이터베이스 연결을 캡슐화하는 클래스입니다.

그렇지 않은 경우 클래스를 만들 필요가 없습니다.


0

그것은 당신의 아이디어와 디자인에 달려 있습니다. OOP보다 훌륭한 디자이너라면 다양한 디자인 패턴의 형태로 자연스럽게 나옵니다. 간단한 스크립트 수준 처리를 위해 OOP가 오버 헤드가 될 수 있습니다. 재사용 및 확장과 같은 OOP의 기본 이점을 간단히 고려하여 필요한지 여부를 확인하십시오. OOP는 복잡한 것을 단순하고 단순하게 만듭니다. OOP를 사용하거나 OOP를 사용하지 않는 방식으로 간단하게 유지하십시오. 어느 것이 더 사용하기 쉽습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.