파이썬 팩토리 함수 모범 사례


30

foo.py클래스가 들어있는 파일이 있다고 가정 해보십시오 Foo.

class Foo(object):
   def __init__(self, data):
      ...

이제 Foo원시 소스 데이터에서 특정 방식으로 객체 를 생성하는 함수를 추가하고 싶습니다 . Foo의 정적 메소드 또는 다른 별도의 함수로 사용해야합니까?

class Foo(object):
   def __init__(self, data):
      ...
# option 1:
   @staticmethod
   def fromSourceData(sourceData):
      return Foo(processData(sourceData))

# option 2:
def makeFoo(sourceData):
   return Foo(processData(sourceData))

사용자에게 편리한 것이 더 중요한지 모르겠습니다.

foo1 = foo.makeFoo(sourceData)

또는 메소드와 클래스 사이의 명확한 연결을 유지하는 것이 더 중요한지 여부 :

foo1 = foo.Foo.fromSourceData(sourceData)

답변:


45

팩토리 기능과 세 번째 옵션 중 하나를 선택해야 합니다. 수업 방법 :

class Foo(object):
   def __init__(self, data):
      ...

   @classmethod
   def fromSourceData(klass, sourceData):
      return klass(processData(sourceData))

클래스 메소드 팩토리에는 상속 가능하다는 추가 이점이 있습니다. 이제의 하위 클래스를 만들 수 있으며 Foo상속 된 팩토리 메서드는 해당 하위 클래스의 인스턴스를 생성합니다.

함수와 클래스 메소드 중 하나를 선택하여 클래스 메소드를 선택합니다. 함수 이름에서 명시 적으로 만들지 않고도 팩토리가 어떤 종류 의 객체를 생산할 것인지를 명확하게 문서화 합니다. 여러 팩토리 메소드뿐만 아니라 여러 클래스가있는 경우 훨씬 명확 해집니다.

다음 두 가지 대안을 비교하십시오.

foo.Foo.fromFrobnar(...)
foo.Foo.fromSpamNEggs(...)
foo.Foo.someComputedVersion()
foo.Bar.fromFrobnar(...)
foo.Bar.someComputedVersion()

vs.

foo.createFooFromFrobnar()
foo.createFooFromSpamNEggs()
foo.createSomeComputedVersionFoo()
foo.createBarFromFrobnar()
foo.createSomeComputedVersionBar()

더 좋은 점은 최종 사용자가 Foo클래스를 가져 와서 모든 팩토리 메소드를 한 곳에 모아 놓아 클래스를 작성할 수있는 다양한 방법으로 사용할 수 있다는 것입니다.

from foo import Foo
Foo()
Foo.fromFrobnar(...)
Foo.fromSpamNEggs(...)
Foo.someComputedVersion()

stdlib datetime모듈 은 클래스 메소드 팩토리를 광범위하게 사용하며 API가 훨씬 명확합니다.


좋은 대답입니다. 에 대한 자세한 내용 은 초보자를위한 @classmethod 및 @staticmethod의 의미를@classmethod 참조하십시오 .
nealmcb

최종 사용자 기능에 중점
drtf

1

파이썬에서는 일반적으로 팩토리 메소드보다 클래스 계층 구조를 선호합니다. 다음과 같은 것 :

class Foo(object):
    def __init__(self, data):
        pass

    def method(self, param):
        pass

class SpecialFoo(Foo):
    def __init__(self, param1, param2):
        # Some processing.
        super().__init__(data)

class FromFile(Foo):
    def __init__(self, path):
        # Some processing.
        super().__init__(data)

전체 계층 구조 (이 계층 만)를 모듈에 넣습니다 (예 :) foos.py. 기본 클래스는 Foo일반적으로 모든 메소드 (및 인터페이스)를 구현하며 일반적으로 사용자가 직접 구성하지는 않습니다. 서브 클래스는 기본 생성자를 덮어 쓰고 구성 방법을 지정하는 수단 Foo입니다. 그런 다음 Foo적절한 생성자를 호출 하여을 만듭니다 .

foo1 = mypackage.foos.SpecialFoo(param1, param2)
foo2 = mypackage.foos.FromFile('/path/to/foo')

정적 메서드, 클래스 메서드 또는 모듈 수준 함수로 작성된 팩토리보다 더 우아하고 유연합니다.

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