Wydaje się, że łączenie Pythona nie koncentruje się na przedmiotach, ale na symbolu, w porównaniu do Ruby lub Smalltalk, z powodów projektowych?

9

Myślałem, że jednym z podstawowych elementów OOP jest to, że mamy przedmioty, którymi jesteśmy zainteresowani, a następnie wysyłamy do nich wiadomości.

Może więc wydawać się naturalne, że mam kolekcję przedmiotów i muszę je ułożyć w jeden sznurek, aby to zrobić:

  ["x", "o", "o"].join(" | ")    # joining a tic-tac-toe row in Ruby

(Smalltalk robi to w ten sam sposób). " | "Jest w jakiś sposób traktowane jako argument, jeden znak, jak się do niej przyłączyć. Może być " "też, jeśli plansza ma być prostsza. Zatem element łączący " | "nie jest czymś, co szczególnie nas interesuje - nie są to główne obiekty w programie, które mają szczególne znaczenie lub znaczenie.

Jeśli Python robi to za pomocą

  " | ".join(["x", "o", "o"])

To trochę dziwne, że prawie czujemy, że przekazujemy argument do argumentu, aby o tym powiedzieć. Może Python jest bardziej proceduralny? Powiedzieć łączącemu łańcuchowi, aby wykonał dla nas jakiś obowiązek?

Czy ma to zapisać implementację, abyśmy nie musieli definiować joindla każdej klasy kolekcji, którą mamy? Ale czy nie jest prawdą, że możemy napisać tylko raz dla dowolnej klasy kolekcji, na przykład w Ruby:

module Enumerable
  def my_join(joiner)
    self.inject {|a,b| a.to_s + joiner + b.to_s}
  end
end

(coś w tym stylu, wzywając to_skażdy element, polegając na to_skażdej klasie, aby wykonać swoją własną rzecz, przekonwertować na ciąg, a następnie połączyć je). Zatem nie musimy implementować dla każdej String, Hash, Set, ani żadnej innej klasy kolekcji, którą mamy.

A może Python się nie zgadza? Używa len("abc")i wydaje się, że type([])zamiast Python3, "abc".len()a [].type()nawet. Czy Python robi to w ten sposób z powodów projektowych?

niepolarność
źródło
7
Z Zen Pythona : „Powinien istnieć jeden - a najlepiej tylko jeden - oczywisty sposób na zrobienie tego. Chociaż na początku taki sposób może nie być oczywisty, chyba że jesteś Holendrem”.
kdgregory
2
W jednej formie kolekcja wie, jak przekonwertować się na ciąg z separatorem, w drugiej ciąg wie, jak połączyć kolekcję, używając siebie jako separatora. Oba są zorientowane obiektowo, ale zmieniają temat i obiekt czasownika.
kdgregory
Maybe Python is more procedural?Python był językiem proceduralnym z kilkoma dodatkami funkcjonalnymi („Python nabył lambda, redukcję (), filter () i map (), dzięki uprzejmości hakera Lisp, który za nimi tęsknił i przesłał łaty robocze”), dopóki coś nie wydaje się być gdzieś w wersji 2. To było około półtorej dekady po pierwszej pracy.
1
I nawet dzisiaj Python nawet nie próbuje być językiem OOP, jest całkowicie paradygmatem.
Podobnie jak C ++, Python jest językiem, który pozwala na OOP. To nie to samo, co język OOP, taki jak Java czy Smalltalk.
Gort the Robot

Odpowiedzi:

9

Pythona przyłączenia jest przeznaczony do pracy na dowolnym iterable . Oznacza to, że projektanci musieli zdecydować, gdzie go umieścić. Ponieważ działa na więcej niż tylko listach, ale zawsze wymaga (separatora) i zwraca ciąg znaków, postanowili włączyć go do typu ciągu.

Armin Ronacher mówi to lepiej niż ja:

http://lucumr.pocoo.org/2011/7/9/python-and-pola/#seemingly-inverse-logic

„Wyobraź sobie, że Python nie działałby w ten sposób. Najpierw musiałbyś przekonwertować iterowalną listę, aby przekonwertować ją na ciąg znaków. Ludzie Ruby będą teraz argumentować, że Ruby rozwiązuje ten problem z mieszaniem modułów, i na pewno mają rację, że to jest opcją. Ale jest to świadoma decyzja projektowa w języku, która ma wiele implikacji. Python zachęca do luźnego łączenia, mając te protokoły, w których rzeczywiste implementacje mogą być gdzie indziej. Jeden obiekt jest iteracyjny, inna część systemu wie, jak to zrobić w ciąg. ”

Scant Roger
źródło
1
OP próbuje rozwiązać ten problem za pomocą tej module Enumeratesekcji, ale Python nie działa w ten sposób, nie ma jednej nadklasy dla wszystkich iteratorów, w której można by umieścić tę metodę.
Próbowałem też w Ruby 2.0 ... Hashi Stringwłaściwie nie mam klasy kolekcji jako superklasy ... ich superklasa jest po prostu Object. Więc te dwie klasy polegają tylko na mieszaniu Enumerable ... coś, co rozumiem, jak interfejs pozwalający na zestaw zachowań kolekcji
nonpolarity
Więc jest to w zasadzie ograniczenie faktu, że „iterowalny” nie jest klasą lub czymś z faktycznym kodem, ale raczej wzorcem pisania kaczki? Alternatywnie, po prostu dlatego, że Python chciał być tak ogólny, aby móc pracować nad dowolną kolekcją z tą samą implementacją (podczas gdy wiele innych standardowych bibliotek po prostu zaimplementowałoby ją dla każdej kolekcji, jeśli faktycznie dotyczy tej kolekcji).
Kat