etc./StackOverFlow

초보자를 위한 @classmethod와 @staticmethod의 의미는? [복제하다]

청렴결백한 만능 재주꾼 2022. 1. 4. 06:05
반응형

질문자 :user1632861


누군가 나에게 파이썬에서 @classmethod@staticmethod 의 의미를 설명해 주시겠습니까? 차이점과 의미를 알아야 합니다.

내가 이해하는 한, @classmethod 는 클래스에 그것이 서브클래스로 상속되어야 하는 메소드이거나... 무언가라고 알려줍니다. 하지만 그게 무슨 소용입니까? @classmethod 또는 @staticmethod 또는 @ 정의를 추가하지 않고 클래스 메서드를 정의하는 것이 어떻습니까?

tl;dr: 언제 사용해야 하고, 사용해야 하며, 어떻게 사용해야 합니까?



classmethodstaticmethod 는 매우 유사하지만 두 엔터티의 사용법에 약간의 차이가 있습니다. classmethod 에는 클래스 개체에 대한 참조가 첫 번째 매개 staticmethod 에는 매개변수가 전혀 없을 수 있습니다.

예시

 class Date(object): def __init__(self, day=0, month=0, year=0): self.day = day self.month = month self.year = year @classmethod def from_string(cls, date_as_string): day, month, year = map(int, date_as_string.split('-')) date1 = cls(day, month, year) return date1 @staticmethod def is_date_valid(date_as_string): day, month, year = map(int, date_as_string.split('-')) return day <= 31 and month <= 12 and year <= 3999 date2 = Date.from_string('11-09-2012') is_date = Date.is_date_valid('11-09-2012')

설명

날짜 정보를 처리하는 클래스의 예를 가정해 보겠습니다(이것이 상용구가 될 것입니다).

 class Date(object): def __init__(self, day=0, month=0, year=0): self.day = day self.month = month self.year = year

이 클래스는 분명히 특정 날짜에 대한 정보를 저장하는 데 사용할 수 있습니다(시간대 정보 없이 모든 날짜가 UTC로 표시된다고 가정하겠습니다).

여기에는 Python 클래스 인스턴스의 일반적인 이니셜라이저인 __init__ 가 있습니다. 이 instancemethod 로 인수를 수신하며 새로 생성된 인스턴스에 대한 참조를 보유하는 첫 번째 비선택 인수( self

클래스 메서드

classmethod 사용하여 훌륭하게 수행할 수 있는 몇 가지 작업이 있습니다.

외부 소스에서 오는 날짜 정보가 'dd-mm-yyyy' 형식의 문자열로 인코딩된 Date 클래스 인스턴스를 만들고 싶다고 가정해 봅시다. 프로젝트 소스 코드의 다른 위치에서 이 작업을 수행해야 한다고 가정합니다.

여기서 우리가 해야 할 일은 다음과 같습니다.

  1. 3개의 정수 변수 또는 해당 변수로 구성된 3개 항목 튜플로 일, 월 및 연도를 수신하도록 문자열을 구문 분석합니다.
  2. 해당 값을 초기화 호출에 전달하여 Date 를 인스턴스화합니다.

이것은 다음과 같이 보일 것입니다:

 day, month, year = map(int, string_date.split('-')) date1 = Date(day, month, year)

이를 위해 C++는 오버로딩을 통해 이러한 기능을 구현할 수 있지만 Python에는 이러한 오버로딩이 없습니다. classmethod 를 사용할 수 있습니다. 다른 " 생성자 "를 만들어 보겠습니다.

 @classmethod def from_string(cls, date_as_string): day, month, year = map(int, date_as_string.split('-')) date1 = cls(day, month, year) return date1 date2 = Date.from_string('11-09-2012')

위의 구현을 더 자세히 살펴보고 여기에 어떤 이점이 있는지 검토해 보겠습니다.

  1. 날짜 문자열 구문 분석을 한 곳에서 구현했으며 이제 다시 사용할 수 있습니다.
  2. 여기에서는 캡슐화가 잘 작동합니다(문자열 구문 분석을 다른 곳에서 단일 함수로 구현할 수 있다고 생각한다면 이 솔루션이 OOP 패러다임에 훨씬 더 적합합니다).
  3. cls 는 클래스의 인스턴스가 아니라 클래스 자체 를 보유하는 객체입니다. Date 클래스를 상속하면 모든 자식에 from_string 정의되기 때문에 매우 좋습니다.

정적 메서드

staticmethod 어떻습니까? classmethod 와 매우 유사하지만 필수 매개변수를 사용하지 않습니다(클래스 메서드 또는 인스턴스 메서드처럼).

다음 사용 사례를 살펴보겠습니다.

어떻게 든 유효성을 검사하려는 날짜 문자열이 있습니다. Date 클래스에도 논리적으로 바인딩되어 있지만 인스턴스화할 필요는 없습니다.

여기에서 staticmethod 가 유용할 수 있습니다. 다음 코드를 살펴보겠습니다.

 @staticmethod def is_date_valid(date_as_string): day, month, year = map(int, date_as_string.split('-')) return day <= 31 and month <= 12 and year <= 3999 # usage: is_date = Date.is_date_valid('11-09-2012')

staticmethod 사용에서 볼 수 있듯이 클래스가 무엇인지에 대한 액세스 권한이 없습니다. 기본적으로 메서드처럼 구문적으로 호출되는 함수일 뿐이지만 객체와 내부(필드 및 다른 방법), classmethod는 수행합니다.


Rostyslav Dzinko

Rostyslav Dzinko의 대답은 매우 적절합니다. 추가 생성자를 만들 때 @classmethod 보다 @staticmethod 선택해야 하는 또 다른 이유를 강조할 수 있다고 생각했습니다.

위의 예에서 Rostyslav는 @classmethod from_string 을 Factory로 사용하여 허용되지 않는 매개변수에서 Date 아래 코드 @staticmethod 로 동일한 작업을 수행할 수 있습니다.

 class Date: def __init__(self, month, day, year): self.month = month self.day = day self.year = year def display(self): return "{0}-{1}-{2}".format(self.month, self.day, self.year) @staticmethod def millenium(month, day): return Date(month, day, 2000) new_year = Date(1, 1, 2013) # Creates a new Date object millenium_new_year = Date.millenium(1, 1) # also creates a Date object. # Proof: new_year.display() # "1-1-2013" millenium_new_year.display() # "1-1-2000" isinstance(new_year, Date) # True isinstance(millenium_new_year, Date) # True

따라서 new_yearmillenium_new_year Date 클래스의 인스턴스입니다.

그러나 자세히 관찰하면 Factory 프로세스는 하드코딩되어 어떤 일이 있어도 Date 이것이 의미하는 바는 Date 클래스가 하위 클래스로 분류 Date 객체를 생성한다는 의미입니다(하위 클래스의 속성 없이). 아래 예에서 확인하세요.

 class DateTime(Date): def display(self): return "{0}-{1}-{2} - 00:00:00PM".format(self.month, self.day, self.year) datetime1 = DateTime(10, 10, 1990) datetime2 = DateTime.millenium(10, 10) isinstance(datetime1, DateTime) # True isinstance(datetime2, DateTime) # False datetime1.display() # returns "10-10-1990 - 00:00:00PM" datetime2.display() # returns "10-10-2000" because it's not a DateTime object but a Date object. Check the implementation of the millenium method on the Date class for more details.

datetime2 DateTime 의 인스턴스가 아닙니까? WTF? @staticmethod 데코레이터가 사용되었기 때문입니다.

대부분의 경우 이는 바람직하지 않습니다. 원하는 것이 그것을 호출한 클래스를 인식하는 Factory 메소드라면 @classmethod 가 필요한 것입니다.

Date.millenium 과 같이 다시 작성합니다(위 코드에서 변경되는 유일한 부분).

 @classmethod def millenium(cls, month, day): return cls(month, day, 2000)

class 가 하드 코딩되지 않고 오히려 학습되도록 합니다. cls 는 모든 하위 클래스가 될 수 있습니다. 결과 object cls 의 인스턴스가 됩니다.
이를 테스트해 보겠습니다.

 datetime1 = DateTime(10, 10, 1990) datetime2 = DateTime.millenium(10, 10) isinstance(datetime1, DateTime) # True isinstance(datetime2, DateTime) # True datetime1.display() # "10-10-1990 - 00:00:00PM" datetime2.display() # "10-10-2000 - 00:00:00PM"

그 이유는 지금까지 알다시피 @classmethod 대신 @classmethod가 사용 @staticmethod


Yaw Boakye

@classmethod 의미: 이 메서드가 호출될 때 해당 클래스의 인스턴스 대신 첫 번째 인수로 클래스를 전달합니다(일반적으로 메서드에서 하는 것처럼). 즉, 특정 인스턴스가 아니라 해당 메서드 내에서 클래스와 해당 속성을 사용할 수 있습니다.

@staticmethod 의미: 이 메소드가 호출될 때 클래스의 인스턴스를 전달하지 않습니다(일반적으로 메소드에서 하는 것처럼). 즉, 클래스 내부에 함수를 넣을 수 있지만 해당 클래스의 인스턴스에 액세스할 수는 없습니다(이는 메서드가 인스턴스를 사용하지 않을 때 유용합니다).


Simeon Visser

각각을 사용할 때

@staticmethod 함수는 클래스 내부에 정의된 @staticmethod 클래스를 먼저 인스턴스화하지 않고 호출할 수 있습니다. 정의는 상속을 통해 변경할 수 없습니다.

  • Python은 객체에 대한 바인딩 메서드 를 인스턴스화할 필요가 없습니다.
  • 코드의 가독성을 높여줍니다. @staticmethod 를 보면 메서드가 객체 자체의 상태에 의존하지 않는다는 것을 알 수 있습니다.

@classmethod 함수도 클래스를 인스턴스화하지 않고 호출할 수 있지만 해당 정의는 상속을 통해 상위 클래스가 아닌 하위 클래스를 따르므로 하위 클래스에서 재정의할 수 있습니다. @classmethod 함수의 첫 번째 인수는 항상 cls (class) 여야 하기 때문입니다.

  • 예를 들어 일종의 사전 처리를 사용하여 클래스의 인스턴스를 만드는 데 사용되는 팩토리 메서드.
  • 정적 메서드를 호출하는 정적 메서드 : 정적 메서드를 여러 정적 메서드로 분할하는 경우 클래스 이름을 하드 코딩하지 말고 클래스 메서드를 사용해야 합니다.

여기 에 이 주제에 대한 좋은 링크가 있습니다.


zangw

@classmethod@staticmethod 의미는?

  • 메서드는 속성으로 액세스할 수 있는 개체의 네임스페이스에 있는 함수입니다.
  • 일반(예: 인스턴스) 메서드는 암시적 첫 번째 인수로 self
  • 클래스 메서드는 암시적 첫 번째 인수로 클래스(보통 cls
  • 정적 메서드는 암시적 첫 번째 인수를 가져오지 않습니다(일반 함수처럼).

언제 사용해야 하며, 왜 사용해야 하며, 어떻게 사용해야 합니까?

데코레이터는 필요 하지 않습니다. 그러나 함수에 대한 인수의 수를 최소화해야 한다는 원칙(Clean Coder 참조)은 그렇게 하는 데 유용합니다.

 class Example(object): def regular_instance_method(self): """A function of an instance has access to every attribute of that instance, including its class (and its attributes.) Not accepting at least one argument is a TypeError. Not understanding the semantics of that argument is a user error. """ return some_function_f(self) @classmethod def a_class_method(cls): """A function of a class has access to every attribute of the class. Not accepting at least one argument is a TypeError. Not understanding the semantics of that argument is a user error. """ return some_function_g(cls) @staticmethod def a_static_method(): """A static method has no information about instances or classes unless explicitly given. It just lives in the class (and thus its instances') namespace. """ return some_function_h()

인스턴스 메서드와 클래스 메서드 모두에서 하나 이상의 인수를 허용하지 않는 것은 TypeError이지만 해당 인수의 의미를 이해하지 못하는 것은 사용자 오류입니다.

( some_function 정의, 예:

 some_function_h = some_function_g = some_function_f = lambda x=None: x

그리고 이것은 작동합니다.)

인스턴스 및 클래스에 대한 점 조회:

인스턴스에 대한 점 조회는 다음 순서로 수행됩니다.

  1. 클래스 네임스페이스의 데이터 디스크립터(예: 속성)
  2. 인스턴스 __dict__
  3. 클래스 이름 공간(메소드)의 비 데이터 설명자.

인스턴스에 대한 점으로 구분된 조회는 다음과 같이 호출됩니다.

 instance = Example() instance.regular_instance_method

메소드는 호출 가능한 속성입니다.

 instance.regular_instance_method()

인스턴스 메서드

인수 self 는 점 조회를 통해 암시적으로 제공됩니다.

클래스의 인스턴스에서 인스턴스 메서드에 액세스해야 합니다.

 >>> instance = Example() >>> instance.regular_instance_method() <__main__.Example object at 0x00000000399524E0>

클래스 메서드

인수 cls 는 점 조회를 통해 암시적으로 제공됩니다.

인스턴스 또는 클래스(또는 하위 클래스)를 통해 이 메서드에 액세스할 수 있습니다.

 >>> instance.a_class_method() <class '__main__.Example'> >>> Example.a_class_method() <class '__main__.Example'>

정적 메서드

암시적으로 인수가 제공되지 않습니다. 이 메서드는 조회할 수 있다는 점을 제외하고 모듈의 네임스페이스에 정의된 모든 함수처럼 작동합니다.

 >>> print(instance.a_static_method()) None

다시 말하지만, 언제 사용해야합니까, 왜 사용해야합니까?

이들 각각은 인스턴스 메소드와 비교하여 메소드를 전달하는 정보에서 점진적으로 더 제한적입니다.

정보가 필요하지 않을 때 사용하십시오.

이렇게 하면 함수와 메서드를 더 쉽게 추론하고 단위 테스트할 수 있습니다.

어느 것이 더 추론하기 쉽습니까?

 def function(x, y, z): ...

또는

 def function(y, z): ...

또는

 def function(z): ...

인수가 적은 함수는 추론하기 쉽습니다. 또한 단위 테스트가 더 쉽습니다.

이들은 인스턴스, 클래스 및 정적 메서드와 유사합니다. 인스턴스가 있을 때 클래스도 있다는 점을 염두에 두고 다시 한 번 스스로에게 물어보십시오. 어느 것이 더 추론하기 쉬울까요?:

 def an_instance_method(self, arg, kwarg=None): cls = type(self) # Also has the class of instance! ... @classmethod def a_class_method(cls, arg, kwarg=None): ... @staticmethod def a_static_method(arg, kwarg=None): ...

내장 예제

다음은 내가 가장 좋아하는 내장 예제입니다.

str.maketrans 정적 메서드는 string str 네임스페이스에서 액세스할 수 있는 것이 훨씬 더 편리합니다.

 >>> 'abc'.translate(str.maketrans({'a': 'b'})) 'bbc'

dict.fromkeys 클래스 메서드는 반복 가능한 키에서 인스턴스화된 새 사전을 반환합니다.

 >>> dict.fromkeys('abc') {'a': None, 'c': None, 'b': None}

서브클래싱되면 클래스 정보를 클래스 메소드로 가져오는 것을 볼 수 있습니다. 이는 매우 유용합니다.

 >>> class MyDict(dict): pass >>> type(MyDict.fromkeys('abc')) <class '__main__.MyDict'>

나의 조언 - 결론

클래스나 인스턴스 인수가 필요없지만, 그 함수는 객체의 사용과 관련이 있고, 객체의 네임스페이스에 있는 것이 편리할 때 정적 메서드를 사용합니다.

인스턴스 정보는 필요하지 않지만 다른 클래스나 정적 메서드에 대한 클래스 정보가 필요하거나 생성자 자체가 필요할 때 클래스 메서드를 사용합니다. (여기서 서브클래스를 사용할 수 있도록 클래스를 하드코딩하지 않습니다.)


Aaron Hall

메서드를 호출하는 하위 클래스에 따라 메서드의 동작을 변경하려는 경우 @classmethod 사용합니다. 클래스 메소드에 호출 클래스에 대한 참조가 있음을 기억하십시오.

정적을 사용하는 동안 하위 클래스에서 동작이 변경되지 않은 상태로 유지되기를 원할 것입니다.

예시:

 class Hero: @staticmethod def say_hello(): print("Helllo...") @classmethod def say_class_hello(cls): if(cls.__name__=="HeroSon"): print("Hi Kido") elif(cls.__name__=="HeroDaughter"): print("Hi Princess") class HeroSon(Hero): def say_son_hello(self): print("test hello") class HeroDaughter(Hero): def say_daughter_hello(self): print("test hello daughter") testson = HeroSon() testson.say_class_hello() #Output: "Hi Kido" testson.say_hello() #Outputs: "Helllo..." testdaughter = HeroDaughter() testdaughter.say_class_hello() #Outputs: "Hi Princess" testdaughter.say_hello() #Outputs: "Helllo..."

Krishnendu Kunti

약간의 편집

@staticmethod 호출되는 객체에 대한 참조 없이 클래스 내부에 메소드를 작성하는 방법입니다. 따라서 self 또는 cls와 같은 암시적 인수를 전달할 필요가 없습니다. 클래스 외부에서 작성된 방식과 정확히 동일하게 작성되지만, 이 메소드는 해당 클래스의 일부가 되어야 하기 때문에 클래스 내부에서 메소드를 캡슐화해야 하는 경우 @staticmethod가 유용하기 때문에 파이썬에서는 아무 소용이 없습니다. 사례.

@classmethod 팩토리 메소드를 작성하고자 할 때 중요하며 이 사용자 정의 속성을 사용하여 클래스에 첨부할 수 있습니다. 이 속성은 상속된 클래스에서 재정의될 수 있습니다.

이 두 가지 방법을 비교하면 다음과 같습니다.

테이블


SIslam

@classmethod

@classmethod __init__ 와 비교할 수 있습니다. __init__() 이라고 생각할 수 있습니다. 이것은 파이썬이 C++에서 클래스 생성자 오버로딩을 실현하는 방식입니다.

 class C: def __init__(self, parameters): .... @classmethod def construct_from_func(cls, parameters): .... obj1 = C(parameters) obj2 = C.construct_from_func(parameters)

둘 다 정의의 첫 번째 인수로 클래스에 대한 참조를 가지고 있는 반면 __init__self 사용하지만 construct_from_func 는 일반적으로 cls

@정적 메서드

@staticmethod object method 와 비교할 수 있습니다.

 class C: def __init__(self): .... @staticmethod def static_method(args): .... def normal_method(parameters): .... result = C.static_method(parameters) result = obj.normal_method(parameters)

Ke Zhang

저는 이 사이트의 초보자이며 위의 모든 답변을 읽었으며 원하는 정보를 얻었습니다. 그러나 나는 투표권이 없습니다. 그래서 StackOverflow를 이해하면서 답변을 시작하고 싶습니다.

  • @staticmethod 는 메소드의 첫 번째 매개변수로 self 또는 cls가 필요하지 않습니다.
  • @staticmethod@classmethod 래핑된 함수는 인스턴스 또는 클래스 변수에 의해 호출될 수 있습니다.
  • @staticmethod @staticmethod 데코레이터에 의해 래핑된 기본 클래스 함수를 덮어쓸 수 없는 일종의 '불변 속성'에 영향을 줍니다.
  • @classmethod 는 함수의 첫 번째 매개변수로 cls(클래스 이름, 원하는 경우 변수 이름을 변경할 수 있지만 권장하지 않음)가 필요합니다.
  • @classmethod 항상 하위 클래스 방식으로 사용되며, 하위 클래스 상속은 기본 클래스 함수의 효과를 변경할 수 있습니다. 즉, @classmethod 래핑된 기본 클래스 함수는 다른 하위 클래스에서 덮어쓸 수 있습니다.

AyiFF

누군가에게 유용할 수도 있는 약간 다른 방식의 생각... 클래스 메서드는 슈퍼클래스에서 다른 자식 클래스에서 호출될 때 해당 메서드가 어떻게 작동해야 하는지 정의하는 데 사용됩니다. 호출하는 자식 클래스에 관계없이 동일한 것을 반환하려는 경우 정적 메서드가 사용됩니다.


boson

간단히 말해서 @classmethod는 일반 메서드를 팩토리 메서드로 바꿉니다.

예를 들어 살펴보겠습니다.

 class PythonBook: def __init__(self, name, author): self.name = name self.author = author def __repr__(self): return f'Book: {self.name}, Author: {self.author}'

@classmethod가 없으면 인스턴스를 하나씩 생성해야 하고 흩어져 있어야 합니다.

 book1 = PythonBook('Learning Python', 'Mark Lutz') In [20]: book1 Out[20]: Book: Learning Python, Author: Mark Lutz book2 = PythonBook('Python Think', 'Allen B Dowey') In [22]: book2 Out[22]: Book: Python Think, Author: Allen B Dowey

예를 들어 @classmethod

 class PythonBook: def __init__(self, name, author): self.name = name self.author = author def __repr__(self): return f'Book: {self.name}, Author: {self.author}' @classmethod def book1(cls): return cls('Learning Python', 'Mark Lutz') @classmethod def book2(cls): return cls('Python Think', 'Allen B Dowey')

테스트:

 In [31]: PythonBook.book1() Out[31]: Book: Learning Python, Author: Mark Lutz In [32]: PythonBook.book2() Out[32]: Book: Python Think, Author: Allen B Dowey

보다? 인스턴스는 클래스 정의 내에서 성공적으로 생성되고 함께 수집됩니다.

결론적으로 @classmethod 데코레이터는 기존의 메서드를 팩토리 메서드로 변환하고, classmethods를 사용하면 필요한 만큼 대체 생성자를 추가할 수 있습니다.


AbstProcDo

클래스 메서드는 클래스 상태를 수정할 수 있으며 클래스에 바인딩되며 매개 변수로 cls를 포함합니다.

정적 메서드는 클래스 상태를 수정할 수 없으며 클래스에 바인딩되어 있으며 클래스 또는 인스턴스를 알지 못합니다.

 class empDetails: def __init__(self,name,sal): self.name=name self.sal=sal @classmethod def increment(cls,name,none): return cls('yarramsetti',6000 + 500) @staticmethod def salChecking(sal): return sal > 6000 emp1=empDetails('durga prasad',6000) emp2=empDetails.increment('yarramsetti',100) # output is 'durga prasad' print emp1.name # output put is 6000 print emp1.sal # output is 6500,because it change the sal variable print emp2.sal # output is 'yarramsetti' it change the state of name variable print emp2.name # output is True, because ,it change the state of sal variable print empDetails.salChecking(6500)

y durga prasad

출처 : http:www.stackoverflow.com/questions/12179271/meaning-of-classmethod-and-staticmethod-for-beginner

반응형