No Python, quando devo usar uma função em vez de um métod

O Zen do Python afirma que deve haver apenas uma maneira de fazer as coisas; no entanto, frequentemente me deparo com o problema de decidir quando usar uma função versus quando usar um métod

Vamos dar um exemplo trivial - um objeto ChessBoard. Digamos que precisamos de alguma maneira de obter todos os movimentos legais do rei disponíveis no tabuleiro. Nós escrevemos ChessBoard.get_king_moves () ou get_king_moves (chess_board)?

Aqui estão algumas perguntas relacionadas que eu olhei:

Por que python usa 'métodos mágicos'? Existe um motivo pelo qual as strings Python não têm um método de comprimento de strin

As respostas que recebi foram amplamente inconclusivas:

Por que o Python usa métodos para algumas funcionalidades (por exemplo, list.index ()), mas funciona para outras (por exemplo, len (list))?

O principal motivo é a história. As funções foram usadas para as operações genéricas para um grupo de tipos e que se destinavam a funcionar mesmo para objetos que não tinham métodos (por exemplo, tuplas). Também é conveniente ter uma função que possa ser aplicada facilmente a uma coleção amorfa de objetos quando você usar os recursos funcionais do Python (map (), apply () et al).

Na verdade, implementar len (), max (), min () como uma função interna é na verdade menos código do que implementá-los como métodos para cada tipo. Pode-se discutir sobre casos individuais, mas isso faz parte do Python e é tarde demais para fazer essas mudanças fundamentais agora. As funções precisam permanecer para evitar a quebra maciça de códig

mbora interessante, o exposto acima não diz muito sobre qual estratégia adota

Essa é uma das razões: com métodos personalizados, os desenvolvedores podem escolher um nome de método diferente, como getLength (), length (), getlength () ou qualquer outro. O Python aplica nomes estritos para que a função comum len () possa ser usad

Um pouco mais interessante. Na minha opinião, as funções são, em certo sentido, a versão Pythonic das interface

Lastly,do próprio Guido:

Falar sobre as Habilidades / Interfaces me fez pensar em alguns de nossos nomes de métodos especiais "desonestos". Na Referência de Linguagem, ele diz: "Uma classe pode implementar determinadas operações que são invocadas por sintaxe especial (como operações aritméticas ou assinatura e fatiamento), definindo métodos com nomes especiais". Mas existem todos esses métodos com nomes especiais como__len__ ou__unicode__ que parecem ser fornecidos para o benefício de funções internas, e não para o suporte à sintaxe. Presumivelmente, em um Python baseado em interface, esses métodos se transformariam em métodos nomeados regularmente em um ABC, para que__len__ se tornari

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

Apesar de pensar um pouco mais, não vejo por que todoss operações @syntactic não apenas invocariam o método apropriado de nome normal em um ABC específico. "< ", por exemplo, provavelmente chamaria"object.lessthan" (ou talvez "comparable.lessthan "). Então, outro benefício seria a capacidade de afastar o Python dessa estranheza de nome mutilado, o que me parece uma melhoria do HCI.

Hm. Não sei se concordo (imagine que: -).

Existem dois bits do "raciocínio Python" que gostaria de explicar primeir

Primeiro, escolhi len (x) sobre x.len () por razões de HCI def __len__() veio muito mais tarde). Na verdade, existem duas razões entrelaçadas, ambas HCI:

(a) Para algumas operações, a notação de prefixo é melhor do que as operações postfix - prefix (e infix!) têm uma longa tradição em matemática, que gosta de notações em que os visuais ajudam o matemático a pensar em um problema. Compare o modo fácil com o qual reescrevemos uma fórmula comox*(a+b) para dentrox*a + x*b à falta de jeito de fazer a mesma coisa usando uma notação OO bruta.

(b) Quando leio o código que dizlen(x) I conhece que está pedindo o comprimento de algo. Isso me diz duas coisas: o resultado é um número inteiro e o argumento é algum tipo de contêiner. Pelo contrário, quando eu leiox.len(), Eu já tenho que saber quex é algum tipo de contêiner implementando uma interface ou herdando de uma classe que possui um padrãolen(). Testemunhe a confusão que ocasionalmente temos quando uma classe que não está implementando um mapeamento tem umget() oukeys(), ou algo que não seja um arquivo tem umwrite() método.

Dizendo a mesma coisa de outra maneira, vejo 'len' como um built-inOperaçã. Eu odiaria perder isso. Não posso dizer com certeza se você quis dizer isso ou não, mas 'def len (self): ...' certamente parece que você deseja rebaixá-lo para um método comum. Eu sou fortemente -1 niss

A segunda parte da lógica do Python que prometi explicar é a razão pela qual escolhi métodos especiais para procurar__special__ e não apenasspecial. Eu estava antecipando muitas operações que as classes podem substituir, algumas padrão (por exemplo,__add__ ou__getitem__), alguns não tão padrão (por exemplo, picles__reduce__ por um longo tempo não teve suporte no código C). Eu não queria que essas operações especiais usassem nomes de métodos comuns, pois classes pré-existentes ou escritas por usuários sem memória enciclopédica para todos os métodos especiais seriam responsáveis por definir acidentalmente operações que eles não pretendiam implementar. , com conseqüências possivelmente desastrosas. Ivan Krstić explicou isso de forma mais concisa em sua mensagem, que chegou depois que eu escrevi tudo isso.

- --Guido van Rossum (página inicial:http: //www.python.org/~guido)

Meu entendimento disso é que, em certos casos, a notação de prefixo faz mais sentido (p.ex. Duck.quack faz mais sentido do que charlatão (Duck) do ponto de vista linguístico.) E, novamente, as funções permitem "interfaces"

Nesse caso, meu palpite seria implementar get_king_moves com base apenas no primeiro ponto de Guido. Mas isso ainda deixa muitas questões em aberto sobre, por exemplo, implementar uma classe de pilha e fila com métodos push e pop similares - eles devem ser funções ou métodos? (aqui eu acho que funções, porque eu realmente quero sinalizar uma interface push-pop)

TLDR: Alguém pode explicar qual deve ser a estratégia para decidir quando usar funções x método