program tip

파이썬에서 언제 메서드 대신 함수를 사용해야합니까?

radiobox 2020. 8. 10. 07:53
반응형

파이썬에서 언제 메서드 대신 함수를 사용해야합니까?


Zen of Python은 작업을 수행 할 수있는 방법은 하나만 있어야한다고 말합니다.하지만 자주 함수를 사용할 때와 메서드를 사용할 때를 결정하는 문제에 직면합니다.

간단한 예로 ChessBoard 객체를 보겠습니다. 보드에서 사용 가능한 모든 합법적 인 King 이동을 얻을 수있는 방법이 필요하다고 가정 해 보겠습니다. 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 ()을 사용할 수 있도록 엄격한 이름 지정을 적용합니다.

약간 더 흥미 롭습니다. 내 생각은 함수는 어떤 의미에서 파이썬 버전의 인터페이스라는 것입니다.

마지막으로, 귀도에서 자신 :

능력 / 인터페이스에 대해 이야기하면서 "불량"특수 메서드 이름 중 일부를 생각하게되었습니다. Language Reference에서 "클래스는 특수한 이름으로 메서드를 정의하여 특수 구문 (예 : 산술 연산 또는 첨자 및 슬라이싱)에 의해 호출되는 특정 연산을 구현할 수 있습니다." 그러나 구문 지원보다는 내장 함수의 이점을 위해 제공되는 __len__or 와 같은 특수 이름을 가진 이러한 모든 메서드가 __unicode__있습니다. 그 때문에 아마도 인터페이스 기반의 파이썬에서, 이러한 방법은 ABC 방송에 정기적으로 명명 된 방법으로 전환 할 __len__될 것

class container:
  ...
  def len(self):
    raise NotImplemented

좀 더 생각해 보면 모든 구문 연산이 특정 ABC에 대해 적절한 일반적으로 명명 된 메서드를 호출 <object.lessthancomparable.lessthan하지 않는 이유를 알 수 없습니다. 예를 들어 " "는 아마도 " "(또는 아마도 " ")를 호출 할 것 입니다. 그래서 또 다른 이점은 파이썬을이 망각 된 이름의 이상 함에서 벗어나게 할 수 있다는 것 입니다.

흠. 동의하는지 잘 모르겠습니다 (그림 :-).

먼저 설명하고 싶은 "Python 근거"가 두 가지 있습니다.

우선, HCI 이유로 x.len () 대신 len (x)를 선택했습니다 ( def __len__()훨씬 나중에 나왔습니다). 실제로 두 가지 이유가 있습니다. 두 가지 모두 HCI입니다.

(a) 일부 연산의 경우 접두사 표기법이 접미사보다 더 잘 읽습니다. 접두사 (및 중위 어!) 연산은 시각적으로 문제에 대해 수학자가 생각하는 데 도움이되는 표기법을 좋아하는 수학에서 오랜 전통을 가지고 있습니다. 우리는 같은 공식을 다시있는 쉬운 비교 x*(a+b)x*a + x*b원시 OO 표기법을 사용하여 같은 일을하고의 어색함에 있습니다.

(b) 내가 무언가의 길이를 요구한다는 len(x)것을 안다 는 코드를 읽을 때 . 이것은 나에게 두 가지를 알려줍니다. 결과는 정수이고 인수는 일종의 컨테이너입니다. 반대로, 내가 읽을 때 x.len(), 나는 그것이 x인터페이스를 구현하거나 표준을 가진 클래스에서 상속받는 일종의 컨테이너 라는 것을 이미 알고 있어야합니다 len(). 매핑을 구현하지 않는 클래스에 get()또는 keys()메서드가 있거나 파일이 아닌 무언가에 메서드 가있을 때 때때로 우리가 혼란스러워하는 것을 목격하십시오 write().

같은 말을 다른 방식으로 말하면 'len'을 내장 연산으로 봅니다. 나는 그것을 잃고 싶지 않습니다. 그 뜻인지 아닌지는 확실하지 않지만 'def len (self) : ...'는 확실히 평범한 방법으로 강등시키고 싶은 것처럼 들립니다. 나는 그것에 대해 강하게 -1입니다.

제가 설명하겠다고 약속 한 두 번째 파이썬 이론적 근거는 제가 __special__단순히 special. 나는 클래스가 재정의하기를 원하는 많은 연산, 일부 표준 (예 : __add__또는 __getitem__), 일부는 그렇게 표준 __reduce__적이 지 않은 연산 (예 : 피클 은 오랫동안 C 코드에서 전혀 지원 하지 않음) 을 예상했습니다 . 이러한 특수 작업이 일반 메서드 이름을 사용하는 것을 원하지 않았습니다. 기존 클래스 또는 모든 특수 메서드에 대한 백과 사전 메모리가없는 사용자가 작성한 클래스는 구현하려는 의도가 아닌 작업을 실수로 정의 할 수 있기 때문입니다. , 비참한 결과를 초래할 수 있습니다. Ivan Krstić는 내가이 모든 것을 쓴 후에 도착한 그의 메시지에서 이것을 더 간결하게 설명했습니다.

---Guido van Rossum (홈페이지 : http://www.python.org/~guido/ )

나의 이해는 어떤 경우에는 접두사 표기법이 더 합리적이라는 것입니다 (즉, Duck.quack이 언어 적 관점에서 quack (Duck)보다 더 의미가 있습니다). 그리고 다시 함수는 "인터페이스"를 허용합니다.

이 경우 Guido의 첫 번째 요점만을 기반으로 get_king_moves를 구현하는 것으로 생각합니다. 그러나 비슷한 푸시 및 팝 메서드로 스택 및 큐 클래스를 구현하는 것과 관련하여 여전히 많은 열린 질문을 남깁니다. 함수 또는 메서드 여야합니까? (여기에서는 푸시-팝 인터페이스를 알리고 싶기 때문에 함수를 추측합니다.)

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."

Moving away from this analogy, why do we use methods and classes? Because we want to contain data and hopefully structure our code in a manner such that it will be reusable and extensible in the future. This brings us to the notion of encapsulation which is so dear to OO design.

The encapsulation principal is really what this comes down to: as a designer you should hide everything about the implementation and class internals which it is not absolutely necessarily for any user or other developer to access. Because we deal with instances of classes, this reduces to "what operations are crucial on this instance". If an operation is not instance specific, then it should not be a member function.

TL;DR: what @Bryan said. If it operates on an instance and needs to access data which is internal to the class instance, it should be a member function.


Use a class when you want to:

1) Isolate calling code from implementation details -- taking advantage of abstraction and encapsulation.

2) When you want to be substitutable for other objects -- taking advantage of polymorphism.

3) When you want to reuse code for similar objects -- taking advantage of inheritance.

Use a function for calls that make sense across many different object types -- for example, the builtin len and repr functions apply to many kinds of objects.

That being said, the choice sometimes comes down to a matter of taste. Think in terms of what is most convenient and readable for typical calls. For example, which would be better (x.sin()**2 + y.cos()**2).sqrt() or sqrt(sin(x)**2 + cos(y)**2)?


Here's a simple rule of thumb: if the code acts upon a single instance of an object, use a method. Even better: use a method unless there is a compelling reason to write it as a function.

In your specific example, you want it to look like this:

chessboard = Chessboard()
...
chessboard.get_king_moves()

Don't over think it. Always use methods until the point comes where you say to yourself "it doesn't make sense to make this a method", in which case you can make a function.


I usually think of an object like a person.

Attributes are the person's name, height, shoe size, etc.

Methods and functions are operations that the person can perform.

If the operation could be done by just any ol' person, without requiring anything unique to this one specific person (and without changing anything on this one specific person), then it's a function and should be written as such.

If an operation is acting upon the person (e.g. eating, walking, ...) or requires something unique to this person to get involved (like dancing, writing a book, ...), then it should be a method.

Of course, it is not always trivial to translate this into the specific object you're working with, but I find it is a good way to think of it.


Generally I use classes to implement a logical set of capabilities for some thing, so that in the rest of my program I can reason about the thing, not having to worry about all the little concerns that make up its implementation.

Anything that's part of that core abstraction of "what you can do with a thing" should usually be a method. This generally includes everything that can alter a thing, as the internal data state is usually considered private and not part of the logical idea of "what you can do with a thing".

When you come to higher level operations, especially if they involve multiple things, I find they are usually most naturally expressed as functions, if they can be built out of the public abstraction of a thing without needing special access to the internals (unless they're methods of some other object). This has the big advantage that when I decide to completely rewrite the internals of how my thing works (without changing the interface), I just have a small core set of methods to rewrite, and then all the external functions written in terms of those methods will Just Work. I find that insisting that all operations to do with class X are methods on class X leads to over-complicated classes.

It depends on the code I'm writing though. For some programs I model them as a collection of objects whose interactions give rise to the behavior of the program; here most important functionality is closely coupled to a single object, and so is implemented in methods, with a scattering of utility functions. For other programs the most important stuff is a set of functions that manipulate data, and classes are in use only to implement the natural "duck types" that are manipulated by the functions.


You may say that, "in the face of ambiguity, refuse the temptation to guess".

However, it's not even a guess. You're absolutely sure that the outcomes of both approaches are the same in that they solve your problem.

I believe it is only a good thing to have multiple ways to accomplishing goals. I'd humbly tell you, as other users did already, to employ whichever "tastes better" / feels more intuitive, in terms of language.

참고URL : https://stackoverflow.com/questions/8108688/in-python-when-should-i-use-a-function-instead-of-a-method

반응형