Python 클래스에서 여러 생성자 메서드 오버로드 및 일반 메서드를 정의하는 방법
"일반 메서드"란 무엇인가요?
다른 유형에 대해 동일한 작업을 구현하는 여러 메서드로 구성된 메서드입니다.
예를 들어
이제 다음과 같은 방법으로 사용자 정의 날짜 클래스(CustomDate
)를 생성해야 하는 요구 사항이 있습니다. CustomDate
):
时间戳
年、月、日(包含三个整数的元组)
ISO 格式的字符串
Datetime
类
一般实现
from datetime import date, datetime class CustomDate: def __init__(self, arg): if isinstance(arg, (int, float)): self.__date = date.fromtimestamp(arg) elif isinstance(arg, tuple) and len(arg) == 3 and all(map(lambda x: isinstance(x, int), arg): self.__date = date(*arg) elif isinstance(arg, str): self.__date = date.fromisoformat(arg) elif isinstance(arg, datetime): self.__date = datetime.date() else: raise TypeError("could not create instance from " + type(arg).__name__) @property def date(): return self.__date
注:这里暂不讨论传入的日期/时间戳合不合法,仅仅只对类型做大致判断。
有没有更好的方式?
我们可以将不同的构建方式拆分为多个方法,并利用 functools
中的 singledispatchmethod
装饰器来根据传入的参数类型决定调用哪个方法。
from datetime import date, datetime from functools import singledispatchmethod class CustomDate: @singledispatchmethod def __init__(self, arg): raise TypeError("could not create instance from " + type(arg).__name__) @__init__.register(int) @__init__.register(float) def __from_timestamp(self, arg): self.__date = date.fromtimestamp(arg) @__init__.register(tuple) def __from_tuple(self, arg): if len(arg) == 3 and all(map(lambda x: isinstance(x, int), arg)): self.__date = date(*arg) else: raise ValueError("could not create instance from a malformed tuple") @__init__.register(str) def __from_isoformat(self, arg): self.__date = date.fromisoformat(arg) @__init__.register(datetime) def __from_datetime(self, arg): self.__date = arg.date() @property def date(self): return self.__date
这样一来,我们便能将每种参数类型的初始化独立成一个个的方法了。
缺点
#1 单分派
在调用期间应该使用哪个方法实现由分派算法决定。如果该算法只基于单个参数的类型来决定使用哪个方法实现,则称其为单分派。
singledispatchmethod
就是就是单分派的。也就是说,只有第一个参数会作为考量。这在实际业务中是远远不足的。
#2 不支持 typing
然而,如上,对元组中元素类型判断还是需要我们用 if
/else
实现。也就是说,我们不能使用 typing.Tuple[int, int, int]
。
作为一种折中的方案,或许我们可以定义一个 ThreeIntTuple
类来对其进行限定,将这些判断从 CustomDate
类中隔离开来。
这里仅提供一个思路让大家参考,我就不实现了(因为我们有更好的方式 xD)。
替代方案:multimethod 库
这个库不是标准库之一,需要通过 pip 安装:
pip install multimethod
优势
multimethod
采用的是多分派算法,能更好地满足更复杂的场景。此外,该库对 typing
中的类型也有不错的支持。
更更好的实践方式
回到上面的问题,我们可以这么改进:
使用
multimethod
方法来替代singledispatchmethod
;使用
Tuple[int, int, int]
来替代tuple
,不再需要手动校验元组的长度和元素类型了;
from datetime import date, datetime from typing import Tuple, Union from multimethod import multimethod class CustomDate: @multimethod def __init__(self, arg): raise TypeError("could not create instance from " + type(arg).__name__) @__init__.register def __from_timestamp(self, arg: Union[int, float]): self.__date = date.fromtimestamp(arg) @__init__.register def __from_tuple(self, arg: Tuple[int, int, int]): self.__date = date(*arg) @__init__.register def __from_isoformat(self, arg: str): self.__date = date.fromisoformat(arg) @__init__.register def __from_datetime(self, arg: datetime): self.__date = arg.date() @property def date(self): return self.__date
究极好的实践方式(真正的方法重载)
在此之前,先问大家一个简单的问题(这跟我们之后的内容有很大的联系):
class A: def a(self): print(1) def a(self): print(2) A().a()
以上这段代码会输出什么?还是会抛出错误?
输出 2
。
在 Python 中,如果定义了重名的方法,最后一个方法是会覆盖掉之前的方法的。
但你或许不知,我们可以通过元类(metaclass)来改变这一行为:
class MetaA(type): class __prepare__(dict): def __init__(*args): pass def __setitem__(self, key, value): if self.get('a'): # Line 7 super().__setitem__('b', value) # Line 8 else: super().__setitem__(key, value) class A(metaclass=MetaA): def a(self): print(1) def a(self): print(2) A().a() # => 1 A().b() # => 2 # Line 22
在第 7 和第 8 行,我们将重名的 a
方法改名为 b
,并在第 22 行成功地调用它了。
multimethod
的维护者们很好地运用了这一点,对重名的方法进行了处理,以达到一种“特殊的效果”。
回到正题,我们可以做出如下改进:
将
multimethod.multidata
设置为CustomDate
类的元类;将所有方法命名为
__init__
- < li>Timestamp
년, 월, 일(3개의 정수를 포함하는 튜플)
🎜Datetime</code > 클래스의 일반 구현 🎜🎜 🎜🎜🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>from datetime import date, datetime
from typing import Tuple, Union
from multimethod import multimeta
class CustomDate(metaclass=multimeta):
def __init__(self, arg: Union[int, float]):
self.__date = date.fromtimestamp(arg)
def __init__(self, arg: Tuple[int, int, int]):
self.__date = date(*arg)
def __init__(self, arg: str):
self.__date = date.fromisoformat(arg)
def __init__(self, arg: datetime):
self.__date = arg.date()
def __init__(self, arg):
raise TypeError("could not create instance from " + type(arg).__name__)
@property
def date(self):
return self.__date</pre><div class="contentsignin">로그인 후 복사</div></div>🎜 참고: 들어오는 날짜/시간 스탬프가 합법적인지 여부에 대해서는 논의하지 않으며 유형에 대해서만 대략적인 판단을 내립니다. 🎜🎜더 좋은 방법이 있나요? 🎜🎜다양한 빌드 방법을 여러 메서드로 분할하고 <code>functools
의 singledispatchmethod
데코레이터를 사용하여 전달된 매개변수 유형에 따라 호출할 메서드를 결정할 수 있습니다. 🎜rrreee🎜이런 방식으로 각 매개변수 유형의 초기화를 별도의 메소드로 분리할 수 있습니다. 🎜🎜단점🎜#1 단일 디스패치
🎜호출 중에 사용해야 하는 메소드 구현은 디스패치 알고리즘에 따라 결정됩니다. 알고리즘이 단일 매개변수의 유형만을 기반으로 사용할 메소드 구현을 결정하는 경우 이를 단일 디스패치라고 합니다. 🎜🎜singledispatchmethod
는 단일 디스패치입니다. 즉, 첫 번째 매개변수만 고려됩니다. 이는 실제 비즈니스에서는 충분하지 않습니다. 🎜#2는 입력을 지원하지 않습니다
🎜그러나 위에서 언급한 것처럼 요소 유형을 결정하려면if
/else
를 사용해야 합니다. 튜플. 즉, typing.Tuple[int, int, int]
를 사용할 수 없습니다. 🎜🎜절충안으로 ThreeIntTuple
클래스를 정의하여 이를 제한하고 이러한 판단을 CustomDate
클래스에서 분리할 수 있습니다. 🎜🎜여기에는 참고용 아이디어일 뿐이며 구현하지는 않겠습니다(더 나은 방법이 있기 때문입니다). 🎜🎜대안: 멀티메소드 라이브러리🎜🎜이 라이브러리는 표준 라이브러리 중 하나가 아니며 pip를 통해 설치해야 합니다. 🎜rrreee🎜Advantages🎜🎜멀티메서드
는 다중 디스패치 알고리즘을 사용하므로 더 나은 요구 사항을 충족할 수 있습니다. 더 복잡한 요구 사항 장면. 또한 라이브러리는 입력
의 유형을 잘 지원합니다. 🎜🎜더 나은 연습🎜🎜위의 질문으로 돌아가서 다음과 같이 개선할 수 있습니다.🎜- 🎜대신
다중 메서드
메서드를 사용하세요. >singledispatchmethod; 🎜🎜 - 🎜
Tuple
을 대체하려면Tuple[int, int, int]
를 사용하세요. 더 이상 튜플을 수동으로 확인할 필요가 없습니다. )의 요소 유형: 🎜rrreee🎜위 코드는 무엇을 출력합니까? 아니면 오류가 발생할까요? 🎜🎜2
를 출력하세요. 🎜🎜Python에서는 동일한 이름의 메소드가 정의되면 마지막 메소드가 이전 메소드를 덮어씁니다. 🎜🎜하지만 메타클래스를 통해 이 동작을 변경할 수 있다는 사실을 모르실 수도 있습니다. 🎜rrreee🎜 7행과 8행에서는 동일한 이름의a
메서드 이름을b
로 바꿉니다. 22번 라인에서 성공적으로 호출합니다. 🎜🎜다중 메서드
의 관리자는 이를 잘 활용하여 "특수 효과"를 달성하기 위해 중복된 이름을 가진 메서드를 처리했습니다. 🎜🎜주제로 돌아가서 다음과 같은 개선 사항을 적용할 수 있습니다. 🎜- 🎜
multimethod.multidata
를CustomDate
로 설정 > 클래스의 메타클래스입니다. 🎜🎜 - 🎜모든 메소드 이름을
__init__
로 지정합니다. 🎜🎜🎜rrreee🎜효과적으로 보면 이는 정적 언어 메서드 오버로딩과 정확히 같습니다! 🎜
- 🎜
위 내용은 Python 클래스에서 여러 생성자 메서드 오버로드 및 일반 메서드를 정의하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

PHP는 주로 절차 적 프로그래밍이지만 객체 지향 프로그래밍 (OOP)도 지원합니다. Python은 OOP, 기능 및 절차 프로그래밍을 포함한 다양한 패러다임을 지원합니다. PHP는 웹 개발에 적합하며 Python은 데이터 분석 및 기계 학습과 같은 다양한 응용 프로그램에 적합합니다.

PHP는 웹 개발 및 빠른 프로토 타이핑에 적합하며 Python은 데이터 과학 및 기계 학습에 적합합니다. 1.PHP는 간단한 구문과 함께 동적 웹 개발에 사용되며 빠른 개발에 적합합니다. 2. Python은 간결한 구문을 가지고 있으며 여러 분야에 적합하며 강력한 라이브러리 생태계가 있습니다.

Sublime 텍스트로 Python 코드를 실행하려면 먼저 Python 플러그인을 설치 한 다음 .py 파일을 작성하고 코드를 작성한 다음 CTRL B를 눌러 코드를 실행하면 콘솔에 출력이 표시됩니다.

PHP는 1994 년에 시작되었으며 Rasmuslerdorf에 의해 개발되었습니다. 원래 웹 사이트 방문자를 추적하는 데 사용되었으며 점차 서버 측 스크립팅 언어로 진화했으며 웹 개발에 널리 사용되었습니다. Python은 1980 년대 후반 Guidovan Rossum에 의해 개발되었으며 1991 년에 처음 출시되었습니다. 코드 가독성과 단순성을 강조하며 과학 컴퓨팅, 데이터 분석 및 기타 분야에 적합합니다.

Python은 부드러운 학습 곡선과 간결한 구문으로 초보자에게 더 적합합니다. JavaScript는 가파른 학습 곡선과 유연한 구문으로 프론트 엔드 개발에 적합합니다. 1. Python Syntax는 직관적이며 데이터 과학 및 백엔드 개발에 적합합니다. 2. JavaScript는 유연하며 프론트 엔드 및 서버 측 프로그래밍에서 널리 사용됩니다.

Golang은 성능과 확장 성 측면에서 Python보다 낫습니다. 1) Golang의 컴파일 유형 특성과 효율적인 동시성 모델은 높은 동시성 시나리오에서 잘 수행합니다. 2) 해석 된 언어로서 파이썬은 천천히 실행되지만 Cython과 같은 도구를 통해 성능을 최적화 할 수 있습니다.

Visual Studio Code (VSCODE)에서 코드를 작성하는 것은 간단하고 사용하기 쉽습니다. vscode를 설치하고, 프로젝트를 만들고, 언어를 선택하고, 파일을 만들고, 코드를 작성하고, 저장하고 실행합니다. VSCODE의 장점에는 크로스 플랫폼, 무료 및 오픈 소스, 강력한 기능, 풍부한 확장 및 경량 및 빠른가 포함됩니다.

메모장에서 Python 코드를 실행하려면 Python 실행 파일 및 NPPEXEC 플러그인을 설치해야합니다. Python을 설치하고 경로를 추가 한 후 nppexec 플러그인의 명령 "Python"및 매개 변수 "{current_directory} {file_name}"을 구성하여 Notepad의 단축키 "F6"을 통해 Python 코드를 실행하십시오.
