파이썬에서는 언제 메소드 대신 함수를 사용해야 합니까?
Python의 Zen은 작업을 수행하는 데 한 가지 방법만 있어야 한다고 말하지만, 함수를 사용할 때와 방법을 사용할 때를 결정하는 문제에 자주 부딪힙니다.
예를 들어 ChessBoard 객체를 살펴보겠습니다.킹의 모든 합법적인 움직임을 보드에서 이용할 수 있는 방법이 필요하다고 가정해 보겠습니다.ChessBoard.get_king_moves()를 쓸까요, 아니면 get_king_moves(chess_board)를 쓸까요?
다음은 제가 살펴본 몇 가지 관련 질문입니다.
제가 받은 대답은 대체로 결론이 나지 않았습니다.
왜 파이썬은 일부 기능(예: list.index())에는 메소드를 사용하지만 다른 기능(예: len(list)에는 메소드를 사용합니까?
주된 이유는 역사입니다.함수는 유형 그룹에 대해 일반적이고 메서드가 전혀 없는 개체(예: 튜플)에서도 작동하도록 의도된 작업에 사용되었습니다.또한 Python(map(), apply() 등의 기능을 사용할 때 무정형 객체 컬렉션에 쉽게 적용할 수 있는 기능이 있으면 편리합니다.
실제로 len(), max(), min()을 내장 함수로 구현하는 것은 실제로 각 유형의 메소드로 구현하는 것보다 코드가 적습니다.사람들은 개별 사례에 대해 불평할 수 있지만, 그것은 Python의 일부이며, 지금 그러한 근본적인 변화를 하기에는 너무 늦었습니다.대규모 코드 손상을 방지하기 위해 기능을 유지해야 합니다.
흥미롭지만, 위의 내용은 어떤 전략을 채택해야 하는지에 대해 별로 언급하지 않습니다.
이것이 바로 사용자 지정 메서드를 사용하면 개발자가 getLength(), length(), getlength() 등 다른 메서드 이름을 자유롭게 선택할 수 있는 이유 중 하나입니다.Python은 일반 함수 len()을 사용할 수 있도록 엄격한 명명을 적용합니다.
조금 더 흥미롭습니다.제 생각에는 어떤 의미에서 기능은 인터페이스의 파이썬 버전이라는 것입니다.
마지막으로 Guido 자신으로부터:
능력/인터페이스에 대해 이야기하면서 "불량한" 특수 메소드 이름에 대해 생각하게 되었습니다.Language Reference에서는 "클래스는 특별한 이름으로 메서드를 정의하여 특수 구문(예: 산술 연산 또는 첨자 및 슬라이싱)에 의해 호출되는 특정 연산을 구현할 수 있습니다."라고 말합니다.하지만 이런 특별한 이름을 가진 모든 방법들이 있습니다.
__len__
또는__unicode__
이는 구문 지원보다는 내장 기능의 이점을 위해 제공되는 것으로 보입니다.아마도 인터페이스 기반 파이썬에서, 이러한 메소드들은 ABC에서 규칙적으로 명명된 메소드들로 바뀔 것입니다.__len__
다가 될 것입니다.class container: ... def len(self): raise NotImplemented
하지만, 좀 더 생각해보면, 왜 모든 구문 연산이 특정 ABC에서 적절한 일반적인 이름의 방법을 호출하지 않는지 모르겠습니다. 예를
<
들어, 는 아마도 "(또는 ")comparable.lessthan
를object.lessthan
호출할 것입니다. 그래서 또 다른 이점은 파이썬이 이러한 망가진 이름의 이상함에서 벗어날 수 있다는 것입니다. 이는 HCI 개선을 의미하는 것으로 보입니다.흠. 저는 동의할 수 없습니다(그림 :-).
제가 먼저 설명하고 싶은 두 가지 "파이썬 이론적 근거"가 있습니다.
저는 이유로 x이 아닌 len)을 했습니다.
def __len__()
훨씬 나중에). 두 실제로두가지두가모이입얽있다. 지두니 HCI다니습혀.어떤 연산에서는 접두사 표기법이 접두사 표기법보다 더 잘 읽힙니다. 접두사(그리고 접두사) 연산은 수학자가 문제에 대해 생각하는 데 시각적으로 도움이 되는 표기법을 좋아하는 수학의 오랜 전통을 가지고 있습니다.다음과 같은 공식을 다시 작성하는 쉬운 방법과 비교해 보십시오.
x*(a+b)
안으로x*a + x*b
미가공 OO 표기법을 사용하여 동일한 작업을 수행하는 것이 서투릅니다.내가 코드를 읽을 때는
len(x)
나는 그것이 어떤 것의 길이를 요구하는 것이라는 것을 알고 있습니다.이것은 제게 두 가지를 알려줍니다. 결과는 정수이고, 인수는 일종의 용기입니다.반대로, 내가 읽을 때.x.len()
그것을 .x
를 상속받는 컨테이너입니다.len()
매핑을 구현하지 않는 클래스에 다음이 있을 때 때때로 발생하는 혼란을 목격합니다.get()
또는keys()
다른은 메드소, 또파이아것닌있이습다니일는▁a▁method,가 있습니다.write()
방법.같은 말을 다른 뜻으로 하면, 저는 'len'을 붙박이 동작으로 봅니다.저는 그것을 잃고 싶지 않습니다.진심인지 아닌지는 확실히 말할 수 없지만, '방어된(자신): ...'은 확실히 평범한 방법으로 격하시키고 싶은 것처럼 들립니다.저는 그것에 대해 강력하게 -1입니다.
한 두 는 제가 입니다.
__special__
만뿐아라니가 .special
재정의하고자 , 표준 저클래가재자예고작하업예, 어떤표준들어를많은는하스의정는)을 예상했습니다.__add__
또는__getitem__
표준이__reduce__
오랫동안 C 코드를 전혀 지원하지 않았습니다.저는 이러한 특별한 작업이 일반적인 메서드 이름을 사용하는 것을 원하지 않았습니다. 모든 특별한 메서드에 대한 백과사전 메모리가 없는 사용자에 의해 작성된 클래스는 구현하려고 의도하지 않은 작업을 실수로 정의할 수 있고, 결과적으로 재앙을 초래할 수 있기 때문입니다.Ivan Krstich는 제가 이 모든 것을 쓴 후에 도착한 그의 메시지에서 이것을 더 간결하게 설명했습니다.
이것에 대한 제 이해는 어떤 경우에는 접두사 표기법이 더 의미가 있다는 것입니다(즉, 덕).quack은 언어학적 관점에서 quack(Duck)보다 더 의미가 있습니다.) 그리고 함수는 "인터페이스"를 허용합니다.
그런 경우, 제 추측으로는 get_king_moves를 Guido의 첫 번째 포인트만을 기반으로 구현하는 것 같습니다.그러나 이는 유사한 푸시 및 팝업 방법으로 스택 및 큐 클래스를 구현하는 것과 관련하여 여전히 많은 미해결 질문을 남깁니다. 기능 또는 방법이어야 합니까?(여기서 저는 기능을 추측할 것입니다. 왜냐하면 저는 정말 푸시팝 인터페이스를 신호로 보내고 싶기 때문입니다.)
TLDR: 기능을 사용할 시기와 방법을 결정하는 전략이 무엇인지 설명할 수 있는 사람이 있습니까?
일반적인 규칙은 다음과 같습니다. 작업이 개체에 대해 수행됩니까? 아니면 개체에 의해 수행됩니까?
개체에 의해 수행되는 경우 구성원 작업이어야 합니다.만약 그것이 다른 것에도 적용될 수 있거나 다른 것에 의해 물체에 행해진다면 그것은 기능(또는 아마도 다른 것의 구성원)이어야 합니다.
프로그래밍을 도입할 때 객체를 자동차와 같은 실제 객체로 설명하는 것은 전통적인 방식입니다(비록 구현이 부정확하지만).오리를 말씀하시는군요, 그렇게 하죠.
class duck:
def __init__(self):pass
def eat(self, o): pass
def crap(self) : pass
def die(self)
....
"객체는 실제 사물" 비유의 맥락에서, 그 물체가 할 수 있는 모든 것에 대한 클래스 방법을 추가하는 것은 "정확한" 것입니다.그래서 오리를 죽이고 싶다고 하면 오리에 .kill()을 추가합니까?아뇨... 제가 알기론 동물들은 자살하지 않습니다그러므로 내가 오리를 죽이고 싶다면 이렇게 해야 합니다.
def kill(o):
if isinstance(o, duck):
o.die()
elif isinstance(o, dog):
print "WHY????"
o.die()
elif isinstance(o, nyancat):
raise Exception("NYAN "*9001)
else:
print "can't kill it."
이 비유에서 벗어나 왜 우리는 방법과 수업을 사용합니까?왜냐하면 우리는 데이터를 저장하고 미래에 재사용 가능하고 확장 가능한 방식으로 코드를 구성하기를 원하기 때문입니다.이를 통해 OOO 설계에 매우 중요한 캡슐화 개념을 이해할 수 있습니다.
캡슐화 원리는 결국 설계자로서 구현 및 클래스 내부에 대한 모든 것을 숨겨야 하며, 사용자나 다른 개발자가 액세스할 필요는 없습니다.클래스 인스턴스를 처리하기 때문에 "이 인스턴스에서 중요한 작업"으로 줄어듭니다.작업이 인스턴스별로 지정되지 않은 경우 구성원 함수가 아니어야 합니다.
TL;DR: @Bryan이 말한 것.인스턴스에서 작동하고 클래스 인스턴스 내부의 데이터에 액세스해야 하는 경우 멤버 함수여야 합니다.
다음을 수행할 때 클래스 사용:
추상화 및 캡슐화를 활용하여 호출 코드를 구현 세부 정보에서 분리합니다.
여러분이 다른 물체를 대체하고 싶을 때 -- 다형성의 이점을 이용합니다.
유사한 개체에 대해 코드를 재사용하려는 경우 - 상속의 이점을 활용합니다.
여러 개체 유형에 걸쳐 적합한 호출에 함수를 사용합니다. 예를 들어, 기본 제공 len 및 repr 함수는 여러 개체에 적용됩니다.
그렇긴 하지만, 선택은 때때로 취향의 문제로 귀결됩니다.일반적인 통화에 가장 편리하고 읽을 수 있는 것이 무엇인지 생각해 보십시오.예를 들어, 어떤 것이 더 나을까요?(x.sin()**2 + y.cos()**2).sqrt()
또는sqrt(sin(x)**2 + cos(y)**2)
?
저는 보통 사람처럼 사물을 생각합니다.
속성은 사용자의 이름, 키, 신발 크기 등입니다.
방법 및 기능은 사용자가 수행할 수 있는 작업입니다.
만약 수술이 이 한 명의 특정인에게 고유한 어떤 것도 요구하지 않고 (그리고 이 한 명의 특정인에 대한 어떤 것도 바꾸지 않고) 어떤 노인에 의해서만 수행될 수 있다면, 그것은 기능이고 그렇게 쓰여져야 합니다.
수술이 사람에게 영향을 미치거나(예: 먹기, 걷기, ...) 이 사람 특유의 무언가가 개입해야 하는 경우(예: 춤추기, 책 쓰기 등), 방법이어야 합니다.
물론, 이것을 당신이 작업하고 있는 특정 대상으로 번역하는 것이 항상 사소한 것은 아니지만, 저는 그것이 그것을 생각하는 좋은 방법이라고 생각합니다.
간단한 경험칙은 다음과 같습니다. 코드가 개체의 단일 인스턴스에 작용하는 경우 메소드를 사용합니다.더 좋은 것은, 함수로 쓸 특별한 이유가 없는 한 방법을 사용하는 것입니다.
특정 예제에서는 다음과 같이 표시합니다.
chessboard = Chessboard()
...
chessboard.get_king_moves()
너무 생각하지 마세요."이것을 하나의 방법으로 만드는 것이 말이 안 된다"고 스스로에게 말할 때까지 항상 방법을 사용하십시오. 이 경우 함수를 만들 수 있습니다.
일반적으로 저는 어떤 것에 대한 논리적 기능을 구현하기 위해 수업을 사용합니다. 그러면 프로그램의 나머지 부분에서 구현을 구성하는 모든 작은 문제에 대해 걱정할 필요 없이 그 문제에 대해 추론할 수 있습니다.
"무엇으로 무엇을 할 수 있는가"라는 핵심 추상화의 일부가 되는 모든 것은 보통 방법이 되어야 합니다.내부 데이터 상태는 일반적으로 "어떤 것으로 무엇을 할 수 있는지"에 대한 논리적 아이디어의 일부가 아닌 개인 데이터로 간주되기 때문에 일반적으로 어떤 것을 변경할 수 있는 모든 것을 포함합니다.
당신이 더 높은 수준의 작업을 할 때, 특히 그것들이 여러 가지를 포함하는 경우, 만약 그것들이 내부에 대한 특별한 접근 없이 어떤 것에 대한 공개 추상화로 구축될 수 있다면, 그것들은 보통 가장 자연스럽게 함수로 표현된다는 것을 알게 됩니다.이것은 (인터페이스를 변경하지 않고) 내 사물이 어떻게 작동하는지에 대한 내부를 완전히 다시 쓰기로 결정할 때, 나는 단지 작은 핵심적인 방법 세트만 가지고 있고, 그 방법들의 관점에서 쓰여진 모든 외부 함수들은 그냥 작동할 것이라는 큰 이점을 가지고 있습니다.클래스 X와 관련된 모든 작업이 클래스 X의 메서드라고 주장하면 클래스가 너무 복잡해집니다.
하지만 제가 쓰는 코드에 따라 다릅니다.일부 프로그램의 경우 상호 작용으로 프로그램의 동작이 발생하는 개체의 집합으로 모델링합니다. 여기서 가장 중요한 기능성은 단일 개체와 밀접하게 결합되므로 유틸리티 함수의 분산과 함께 방법으로 구현됩니다.다른 프로그램에서 가장 중요한 것은 데이터를 조작하는 함수의 집합이며, 클래스는 함수에 의해 조작되는 자연스러운 "오리 유형"을 구현하기 위해 사용됩니다.
@thriveth의 대답에 대한 @endolith의 논평에서 더 나아가:
키(사람) 대 사람키는 사과와 치즈를 비교하는 것이라고 생각합니다.
이는 명명 규칙과 함수 및 구성원의 올바른 명명으로 요약됩니다.인칭의키는 아마 사람이어야 할 것입니다.hight_in_hight(또는 그와 같은)와 hight(사람)는 (사람)의_hight(높이) 또는 what_is_hight(높이) 또는 measure_hight(높이)가 될 수 있으며 (사람)의 키는 (사람)의_hight(높이)가 되어야 합니다. 그런 다음 '높이'가 사라집니다.
기능은 무엇인가를 하고 있습니다(단, 돌아오는 사람이라도).키가 가장 안 좋은 경우)인 반면에 사람.키는 사람의 어떤 속성입니다.
언급URL : https://stackoverflow.com/questions/8108688/in-python-when-should-i-use-a-function-instead-of-a-method
'programing' 카테고리의 다른 글
TypeScript에서 각 루프를 끊는 방법 (0) | 2023.08.21 |
---|---|
요소 너비를 만드는 방법: 100% - 패딩? (0) | 2023.08.21 |
파이썬처럼 자바스크립트로 된 사전이 있습니까? (0) | 2023.08.21 |
AV Player 대리자가 없습니까?노래가 재생되면 추적하는 방법은 무엇입니까?목표 아이폰 개발 (0) | 2023.08.01 |
@Transactional은 어디에 두나요?인터페이스 사양 또는 구현 시? (0) | 2023.08.01 |