2013-12-18 2 views
28

아마도 이것은 기술적 인 것보다 스타일에 관한 질문 일 뿐이지 만 여러 멤버 변수가있는 파이썬 클래스가 있고 일부 멤버 변수가 사용자가 처음에 클래스의 인스턴스를 만들 때 (예 : __init__ 함수) 초기화되고 나중에 호출 될 멤버 함수의 인수에서 다른 멤버 변수를 정의하려고합니다. 그래서 내 질문에 __init__ 함수에있는 모든 멤버 변수를 초기화해야합니다 (그리고 더미 값을 나중에 정의됩니다 것들을 설정) 또는 일부는 __init__ 함수와 일부 기능을 나중에 초기화해야합니다. 이것이 이해하기 어려울 수도 있다는 것을 알고 있습니다. 그래서 몇 가지 예가 있습니다.파이썬 - 모든 멤버 변수를 __init__에서 초기화해야합니까?

이 예제에서는 함수에서 처음 0으로 설정 한 다음 나중에 my_funct 함수에서 원하는 값으로 설정합니다.

class myClass(object): 
    def __init__(self,var1,var2): 
     self.var1=var1 
     self.var2=var2 
     self.var3=0 

    def my_funct(self,var3): 
     self.var3=var3 

이 예에서는

, var3은 내가 생각하지 않는다

class myClass(object): 
    def __init__(self,var1,var2): 
     self.var1=var1 
     self.var2=var2 

    def my_funct(self,var3): 
     self.var3=var3 

__init__ 기능에 전혀 정의되지 않은 큰 차이 (메모리 사용량 어쩌면 약간의 차이)를 만들 것 어느 쪽이든 . 그러나 이들 중 하나가 다른 이유로 선호되는 것인지 궁금합니다.

답변

19

객체 지향 프로그래밍에서는 객체가 인스턴스 생성 후 및 메소드 완료 후에 항상 일관된 상태에 있음을 보장하는 것은 개발자의 몫입니다. 그 외에는 원하는대로 클래스를 개발할 수 있습니다 (서브 클래 싱/재정의 등의 특정 원칙을 명심하십시오).

Pylint과 같은 도구는 __init__ 외부에서 인스턴스 변수를 설정할 때 경고합니다. __init__에있는 모든 인스턴스 변수를 설정하는 것이 더 깔끔하지만 항상 준수해야하는 규칙은 아니라고 주장 할 수 있습니다.

+1

동의했다. 일관성이 중요합니다. 외부인이 API 또는 클래스를 유효하지 않은 상태로 사용하는 것을 원하지 않습니다. –

+0

'일관된 상태'의 의미를 간단히 정의 할 수 있습니까? 인스턴스화 후에 새로운 멤버 변수를 추가해야한다는 것을 의미합니까? – user1893354

+1

@ user1893354 인스턴스화 후에 변수를 추가 할 수는 있지만 객체를 만들고 하나 이상의 메소드를 호출하여 지저분한 객체로 끝낼 수 없어야합니다. 메서드와 반환 값의 동작은 항상 일치해야합니다. 예를 들어, 우리는'깨진'과'제대로 작동하는'것을보고하는'Car' 클래스를 가질 수 없습니다. –

3

실제로는 항상 필요하지 않은 변수 초기화를 임의의 기본값으로 __init__에서하지 않는 것이 좋습니다.

이런 경우에는 OO 사용에 의문이 생기지 만, __init__이 모든 것을 수행하지는 않지만 타당하고 이해할 수있는 경우가있을 것이라고 확신합니다. 클래스는 추가 특성을 추가하여 추가로 수정하려고합니다. 다른 방법.

내 생각에 적절한 방법은 변수가 사용하고자하는 방법을 실행하는 동안 설정되어 있는지 테스트하려면 hasattr을 사용하는 것입니다. 이것은 이것이 방법을 사용하는 유효한 방법이고, 테스트가 합당한 방법으로 행동을 바꾸는 경우입니다.

또 다른 방법은이를 사용하고 예외를 처리하고 클래스 사용자가 잘못하고있는 것에 대한 사용자 친숙한 정보를 제공하는 것입니다. 이것은 메소드가 실행 전에 속성을 설정해야하는 경우입니다.

즉, 안녕하세요. 클래스를 초기화했지만 z_run 메서드를 실행하기 전에 z_init 메서드를 호출하여 z 특성이 있는지 확인해야합니다.

또 다른 파이썬 방법은 문서화 문자열에서 메소드를 사용하는 방법을 문서화 한 다음 부적절하게 사용되면 예외를 처리하도록하는 것입니다. 이것은 무언가를 처음으로 구현할 때 충분하므로 다음 작업에 집중할 수 있습니다. 이것은 위와 같은 상황에 있으며 메서드는 속성을 설정해야합니다.

변수를 임의의 기본값으로 초기화한다는 생각이 맘에 들지 않는 이유는 (임의적이기 때문에) 혼란스럽고 라인 노이즈라는 것입니다.

값이 이 아니고이 아니며 단순히 변경할 수있는 기본값 인 경우 __init__ 메서드에서 기본값을 사용해야하며이 값을 재정의 할 수 있습니다. 실제로 유효한 초기 상태 일 수도 있습니다. 이 아니며이 아니므로 __init__ 메소드에서 설정해야합니다.

에 달려 있으며, 다른 방법으로 속성을 추가하거나 임의의 값으로 속성을 초기화하여이 작업을 수행하는 경우 OO 사용을 자제해야합니다.

시므온 비서 (Simeon Visser)는 개체를 일관된 상태로 유지한다고 말하지만 추상적 인 예를 기반으로 일관성을 유지할 근거가 없습니다. Pylint가 이런 종류의 경고를하는 동안, 린트 프로그램의 경고는 단순히 높은 수준의 평론가가 보통 코드 냄새를 나타내는 것을 경고 할 수 있도록하기위한 것입니다. 실제 평론가가 모든 코드를 읽고 이해해야하며 따라서 Pylint가 실제로 필요하지 않기 때문에 고위 평론가에게 말합니다.

엄지 손가락의 규칙을 나누기 예 :

class Mutant(object): 
    """A mutant!""" 

    def __init__(self): 
     """A mutant is born with only 1 eye and 1 mouth""" 

     self.eyes = 1 
     self.mouth = 1 
     self.location = 'Montana' 

    def roll_to(self, location): 
     """If they have limbs, running is less dangerous""" 

     if hasattr(self, 'limbs'): 
      print 'Your mutant broke its limbs off!!' 
      del self.limbs 

     self.location = location 

    def run_to(self, location): 
     """If they don't have limbs, running is not effective""" 

     if not hasattr(self, 'limbs'): 
      print 'Your mutant tries to run but he has no limbs.' 
     else: 
      self.location = location 

    def grow_limbs(self, number_of_limbs): 
     """Ah, evolution!""" 

     assert number_of_limbs > 0, 'Cannot grow 0 or less limbs...' 

     if hasattr(self, 'limbs'): 
      self.limbs += number_of_limbs 
     else: 
      self.limbs = number_of_limbs 
+0

좋은 지적. 멤버 변수 중 하나가 개체 내에서 저장하려는 멤버 함수의 출력 인 경우를 생각하고있었습니다. 이 경우 변수는 멤버 함수가 호출 된 후에 만 ​​실제 값으로 인스턴스화 할 수 있습니다. – user1893354

+0

예를 들어, 'obj'가'output_complex_calculation'을 가지고 있고,'obj.set_result_of_complex_calculation (obj.output_of_complex_calculation())'을 –

+0

으로하고 싶다면, 예를 들어, 클래스는 사용자가 인스턴스 생성시 모델의 매개 변수를 입력하는 예측 모델입니다. 그런 다음 사용자는 예측 목록을 만드는 .predict() 함수를 호출합니다. 그러나이 객체에 대한 이러한 예측을 멤버 변수로 저장하려고합니다. 그러면 다른 멤버 함수가이 새로운 예측 멤버 변수로 무언가를 할 것입니다. 따라서이 경우 예측 멤버 변수의 실제 값은 .predict()가 호출 된 후에 만 ​​인스턴스화 될 수 있습니다. – user1893354

관련 문제