파이썬에서 클래스를 어떻게 디자인합니까?


143

발에서 발발가락 을 감지하는 이전 질문에 정말 도움 이되었지만 이러한 모든 솔루션은 한 번에 한 번만 측정됩니다.

이제 나는 구성된 데이터 가 있습니다.

  • 약 30 마리;
  • 각각 24 개의 측정 값이 있습니다 (여러 개의 하위 그룹으로 나누어 짐).
  • 각 측정에는 적어도 4 개의 접점 (각 발마다 하나씩)이 있으며
    • 각 접점은 5 개 부분으로 나누어 져 있으며
    • 접촉 시간, 위치, 총 힘 등과 같은 여러 매개 변수가 있습니다.

대체 텍스트

분명히 모든 것을 하나의 큰 객체에 집어 넣는 것은 자르지 않을 것이므로 현재의 많은 함수 대신 클래스를 사용해야한다고 생각했습니다. 그러나 클래스에 대한 Python 학습 장을 읽었지만 내 코드에 적용하지 못합니다 ( GitHub 링크 )

또한 정보를 얻을 때마다 모든 데이터를 처리하는 것이 다소 이상하다고 생각 합니다. 각 발의 위치를 ​​알고 나면 이것을 다시 계산할 이유가 없습니다. 또한, 같은 강아지의 모든 발을 비교하여 어떤 접촉이 어느 발에 속하는지 결정합니다 (앞 / 뒤, 왼쪽 / 오른쪽). 함수 만 계속 사용하면 문제가 될 수 있습니다.

그래서 나는 합리적인 방식으로 내 데이터 ( 한 개의 압축 된 데이터에 연결)를 처리 할 수있는 클래스를 만드는 방법에 대한 조언을 찾고 있습니다 .


4
sqlite : docs.python.org/library/sqlite3.html 과 같은 데이터베이스 사용을 고려할 수도 있습니다 . 거대한 데이터 파일을 읽고 데이터베이스 테이블의 행으로 변환하는 프로그램을 작성할 수 있습니다. 그런 다음 두 번째 단계로 데이터베이스에서 데이터를 가져와 추가 분석을 수행하는 프로그램을 작성할 수 있습니다.
unutbu

내가 여기 @ubutbu 와 같은 것을 의미 합니까? 나는 그렇게 할 계획이지만 먼저 모든 데이터를보다 체계적인 방식으로 처리하고 싶습니다
Ivo Flipse

답변:


434

수업을 디자인하는 방법.

  1. 단어를 적어 두십시오. 이 작업을 시작했습니다. 어떤 사람들은 왜 문제가 있는지 궁금해하지 않습니다.

  2. 단어 집합을 이러한 개체가 수행 할 작업에 대한 간단한 설명으로 확장하십시오. 다시 말해,이 일들에 대해 수행 할 다양한 계산을 적어 두십시오. 연락처 당 30 개의 개, 24 개의 측정, 4 개의 연락처 및 여러 개의 "매개 변수"목록이 흥미롭지 만 이야기의 일부일뿐입니다. 개체 디자인의 다음 단계는 "각 발의 위치"와 "같은 발의 모든 발을 비교하여 어떤 접촉이 어느 발에 속하는지 결정합니다"입니다.

  3. 명사에 밑줄을 긋습니다. 진심으로. 일부 사람들은 이것의 가치에 대해 토론하지만 처음 OO 개발자에게는 도움이된다는 것을 알았습니다. 명사에 밑줄을 긋습니다.

  4. 명사를 검토하십시오. "매개 변수"및 "측정"과 같은 일반 명사는 문제 영역의 문제에 적용되는 구체적이고 구체적인 명사로 대체해야합니다. 구체적인 사항은 문제를 명확히하는 데 도움이됩니다. 제네릭은 단순히 세부 사항을 제거합니다.

  5. 각 명사 ( "contact", "paw", "dog"등)에 대해 해당 명사의 속성과 해당 객체가 관여하는 동작을 기록하십시오. 이것을 바로 잡지 마십시오. 모든 속성. 예를 들어 "데이터 세트에 개 30 마리가 포함되어 있습니다"는 중요합니다.

  6. 각 속성에 대해 정의 된 명사 또는 문자열 또는 부동 소수점과 같은 다른 종류의 "원시"또는 "원자"데이터와의 관계인지 여부를 식별 할 수 없습니다.

  7. 각 조치 또는 조작마다 책임이있는 명사와 참여하는 명사를 식별해야합니다. "변동성"의 문제입니다. 일부 개체는 업데이트되고 다른 개체는 업데이트되지 않습니다. 가변성 개체는 돌연변이에 대한 전적인 책임을 가져야합니다.

  8. 이 시점에서 명사를 클래스 정의로 변환 할 수 있습니다. 일부 집단 명사는 목록, 사전, 튜플, 세트 또는 명명 된 튜플이므로 많은 작업을 수행 할 필요가 없습니다. 다른 클래스는 복잡한 파생 데이터 또는 일부 업데이트 / 돌연변이로 인해 더 복잡합니다.

unittest를 사용하여 각 클래스를 개별적으로 테스트하는 것을 잊지 마십시오.

또한 클래스를 변경할 수 있어야한다고 말하는 법은 없습니다. 예를 들어, 변경 가능한 데이터가 거의 없습니다. 당신이 가진 것은 소스 데이터 셋의 변환 함수에 의해 생성 된 파생 된 데이터입니다.


24

다음 충고 (@ S.Lott의 충고와 유사)는 Beginning Python : 초보자부터 전문가까지

  1. 문제에 대한 설명을 작성하십시오 (문제는 어떻게해야합니까?). 모든 명사, 동사 및 형용사에 밑줄을 긋습니다.

  2. 잠재적 클래스를 찾기 위해 명사를 살펴보십시오.

  3. 동사를 살펴보고 잠재적 인 방법을 찾으십시오.

  4. 형용사를 살펴보고 잠재적 인 속성을 찾으십시오.

  5. 메소드와 속성을 클래스에 할당

수업을 개선하기 위해이 책은 또한 우리가 다음을 할 수 있다고 조언합니다.

  1. 프로그램 사용 방법에 대한 시나리오 인 일련의 사용 사례를 작성 하십시오. 모든 기능을 다룰 것.

  2. 모든 사용 사례를 단계별로 생각하여 필요한 모든 것을 다룰 수 있도록하십시오.


우리가 작성해야 할 문장의 예를 갖는 것이 좋을 것입니다.
endolith

14

저는 TDD 접근 방식이 마음에 듭니다. 따라서 원하는 행동에 대한 테스트를 작성하여 시작하십시오. 그리고 통과하는 코드를 작성하십시오. 이 시점에서 디자인에 대해 너무 걱정하지 말고 테스트 스위트와 소프트웨어를 구입하십시오. 복잡한 방법으로 하나의 큰 추악한 클래스로 끝나더라도 걱정하지 마십시오.

때때로,이 초기 프로세스 중에 테스트 가능성을 위해 테스트하기 어렵고 분해해야하는 동작을 찾을 수 있습니다. 이것은 별도의 클래스가 필요하다는 힌트 일 수 있습니다.

그렇다면 재미있는 부분은 ... 리팩토링입니다. 소프트웨어를 작업 한 후에 복잡한 부분을 볼 수 있습니다. 종종 행동의 작은 포켓이 분명 해져서 새로운 클래스를 제안하지만 그렇지 않은 경우 코드를 단순화하는 방법을 찾으십시오. 서비스 객체 및 값 객체를 추출합니다. 방법을 단순화하십시오.

git을 올바르게 사용하고 있다면 (git을 사용하고 있습니까?) 리팩토링 중에 특정 분해를 매우 빠르게 실험 한 다음 포기하고 다시 단순화하지 않으면 되돌릴 수 있습니다.

테스트 된 작업 코드를 먼저 작성하면 디자인 우선 접근 방식으로는 쉽게 얻을 수없는 문제 영역에 대한 통찰력을 얻을 수 있습니다. 테스트와 코드를 작성하면 "어디에서 시작합니까"마비를 지나칠 수 있습니다.


1
나도이 답변에 동의하지만, 문제를 분류하고 가능한 클래스를 식별하는 것 (즉, "충분한"소프트웨어 아키텍처를 수행하는 것)이 여러 팀 구성원이 동시에 문제를 해결할 경우 매우 유용 할 수 있습니다.
벤 스미스

3

OO 디자인의 전체 아이디어는 코드 맵을 문제에 맞게 만드는 것입니다. 예를 들어 강아지의 첫 발자국을 원할 때 다음과 같은 작업을 수행하십시오.

dog.footstep(0)

이제 귀하의 경우 원시 데이터 파일을 읽고 발자국 위치를 계산해야 할 수도 있습니다. 이 모든 것을 footstep () 함수에 숨겨서 한 번만 발생하도록 할 수 있습니다. 다음과 같은 것 :

 class Dog:
   def __init__(self):
     self._footsteps=None 
   def footstep(self,n):
     if not self._footsteps:
        self.readInFootsteps(...)
     return self._footsteps[n]

[이제 일종의 캐싱 패턴입니다. 처음으로 발자국 데이터를 읽고 읽을 때 다음 번에는 self._footsteps에서 가져옵니다.]

그러나 OO 디자인을 올바르게하는 것은 까다로울 수 있습니다. 데이터에 대해하고 싶은 일에 대해 더 많이 생각하면 어떤 클래스에 어떤 방법을 적용해야하는지 알려줍니다.


2

명사, 동사, 형용사를 쓰는 것은 훌륭한 접근 방법이지만, 클래스 디자인은 어떤 데이터를 숨겨야하는지 질문하는 것으로 생각하고 싶습니다.

Query객체와 객체 가 있다고 상상해보십시오 Database.

Query함수는 쿼리를 작성하고 저장하는 데 도움이됩니다. 함수는 함수를 사용하여 쿼리를 쉽게 작성할 수 있으므로 여기에서 핵심입니다. 어쩌면 당신은 머물 수 있습니다 : Query().select('Country').from_table('User').where('Country == "Brazil"'). 구문은 중요하지 않습니다. 바로 그 일입니다! -열쇠는 객체가 무언가숨기는 것을 돕는 것 입니다.이 경우 쿼리를 저장하고 출력하는 데 필요한 데이터입니다. 객체의 힘은 객체를 사용하는 구문 (이 경우에는 영리한 체인)에서 작동하며 객체를 저장하기 위해 저장할 필요가 없습니다. 제대로 완료되면Query 개체가 둘 이상의 데이터베이스에 대한 쿼리를 출력 할 수 있습니다. 내부적으로 특정 형식을 저장하지만 출력 할 때 다른 형식으로 쉽게 변환 할 수 있습니다 (Postgres, MySQL, MongoDB).

이제 Database객체를 생각해 봅시다 . 이것은 무엇을 숨기고 저장합니까? 데이터베이스의 전체 내용을 저장할 수는 없습니다. 데이터베이스가 있기 때문입니다! 그래서 요점이 뭐야? 목표는 오브젝트 를 사용하는 사람들로부터 데이터베이스가 작동하는 방식숨기는 것입니다 Database. 좋은 클래스는 내부 상태를 조작 할 때 추론을 단순화합니다. 이를 위해Database 개체의 경우 네트워킹 호출 작동 방식을 숨기거나 쿼리 또는 업데이트를 일괄 처리하거나 캐싱 계층을 제공 할 수 있습니다.

문제는이 Database개체가 거대하다는 것입니다. 데이터베이스에 액세스하는 방법을 나타내므로 표지 아래에서 모든 작업을 수행 할 수 있습니다. 분명한 네트워킹, 캐싱 및 일괄 처리는 시스템에 따라 처리하기가 매우 어렵 기 때문에 숨기는 것이 매우 유용합니다. 그러나 많은 사람들이 알다시피 데이터베이스는 매우 복잡하며 원시 DB 호출에서 멀어 질수록 성능을 조정하고 일이 어떻게 작동하는지 이해하는 것이 더 어렵습니다.

이것이 OOP의 기본적인 균형입니다. 올바른 추상화를 선택하면 코딩이 간단 해집니다 (문자열, 배열, 사전). 너무 큰 추상화 (데이터베이스, EmailManager, NetworkingManager)를 선택하면 작동 방식 또는 수행 할 작업을 실제로 이해하기에는 너무 복잡해질 수 있습니다. 배고 있다. 목표는 복잡성숨기는 것이지만 약간의 복잡성이 필요합니다. 경험상 가장 좋은 방법은 Manager객체 를 피하고 대신 클래스 structs를 만드는 것입니다. 데이터를 보유하고 조작하는 데 도움이되는 도우미 메서드를 사용하여 데이터를 보유하는 것만으로도 편리합니다. 예를 들어, 경우에 EmailManager함수 호출로 시작 sendEmail하는이 얻어 Email개체. 이것은 간단한 시작점이며 코드는 이해하기 매우 쉽습니다.

예를 들어, 원하는 것을 계산하기 위해 어떤 데이터가 함께 있어야하는지 생각해보십시오. 예를 들어, 동물이 얼마나 멀리 걷는 지 알고 싶을 경우 AnimalStepAnimalTrip(AnimalSteps 모음) 클래스를 가질 수 있습니다 . 이제 각 여행에 모든 단계 데이터가 있으므로 이에 대한 정보를 알아낼 수 있어야합니다 AnimalTrip.calculateDistance().


2

연결된 코드를 감추고 나면 이 시점에서 Dog 클래스를 디자인 하지 않는 것이 좋습니다 . 대신 Pandasdataframes 를 사용해야합니다 . 데이터 프레임은 열이있는 테이블입니다. 당신 dataframe과 같은 열이 같습니다 dog_id,contact_part , contact_time, contact_location, 등을 판다는 뒤에서 NumPy와 배열을 사용하고, 그것은 당신을위한 많은 편리한 메소드가 있습니다 :

  • 예를 들어 개를 선택하십시오 : my_measurements['dog_id']=='Charly'
  • 데이터를 저장하십시오. my_measurements.save('filename.pickle')
  • pandas.read_csv()텍스트 파일을 수동으로 읽는 대신 사용하는 것이 좋습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.