Это сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Одно из различий Python и JavaScript

Чем дальше, тем между большим количеством языков программирования мне приходится переключаться. Одно из различий объектной модели Пайтона и ДжаваСкрипта мне портит кровь (у них парадигмы ООП вообще сильно различаются), если я вовремя не соображу, что надо переключиться с одного языка на другой.

Суть в том, что в Пайтоне метод ходит в гости со своим контекстом:

class A:
    test = 'A'
    def show(self): print self.test

class B: test = 'B'

a, b = A(), B()

show = a.show
b.show = a.show

show() # A
b.show() # A

Тогда как в JavaScript такой код будет работать совершенно иначе, там методы в чужой монастырь со своим уставом не ходят (если их не попросить):

var test = 'global';

A = function () {
    this.test = 'A',
    this.show = function () { alert(this.test) }
};

B = function () { this.test = 'B'; }

a = new A(); b = new B();

b.show =  a.show
show = a.show

show() // global
b.show() // B
b.show.apply(a) // A

Появление «global» наверное надо разъяснить тем, кто JS знает плохо. На самом деле первая строчка (в данном случае) может читаться как «window.test = ’global’», а «show = a.show» как «window.show = a.show», тогда, должно быть, всё более-менее встаёт на свои места.

10 комментариев
zero_sharp 2011

Вы просто не умеете правильно питон готовить.
Любой нормальный программист на питоне знает, что чем чаще в коде повторяется знак подчёркивания, тем код объектно-ориентированней.
В вашем случае достаточно сделать так:

b.show = A.__dict__[’show’].__get__(b, B)

И всё заработает, как в яваскрипте.

Евгений Степанищев (bolknote.ru) 2011

Комментарий для zero_sharp:

Вы какой-то странный вывод из моего рассказа сделали.

В рассказе не было ничего про то, что я не могу вызвать метод в другом контексте, там было про различия поведения похожего по смыслу кода в разных языках.

zero_sharp 2011

On a totally different note, подобное присваивание методов в питоне мне кажется дурным тоном.
Чего Вы хотите подобным кодом добиться в обоих случаях? «Пересадки» методов? В питоне для этого есть классы и наследование.

Евгений Степанищев (bolknote.ru) 2011

Комментарий для zero_sharp:

Ну и, кстати, почему не

b.show = a.show.__func__.__get__(b, b.__class__)

Евгений Степанищев (bolknote.ru) 2011

Комментарий для zero_sharp:

On a totally different note, подобное присваивание методов в питоне мне кажется дурным тоном.

Вы упорно пытаетесь что-то додумать к заметке. Это не какой-то реальный код приложения, а иллюстрация различий.

Ничего страшного, кстати, в таком переносе функционала нет. Обычное «подмешивание» методов, просто у Пайтона этот функционал никак особо не выделен, но это ещё не значит, что его нельзя применять.

Евгений Степанищев (bolknote.ru) 2011

Комментарий для zero_sharp:

Под «подмешиванием» я имею ввиду то, что обычно называется «traits» или «method mix-in».

Евгений Степанищев (bolknote.ru) 2011

Комментарий для zero_sharp:

Если хочется более-менее реального кода, а не чистой демонстрации, то будет что-то вроде следующего.

JS:
var method = expr ? a.show : b.show


method()

Python:
method = a.show if expr else b.show


method()

Результат будет сильно разный.

Азат Разетдинов (razetdinov.ya.ru) 2011

В ES5 для сохранения контекста появился .bind():
b.show = a.show.bind(b)

Евгений Степанищев (bolknote.ru) 2011

Комментарий для razetdinov.ya.ru:

Я знаю, Азат, спасибо! :)

Ivan 2016

А не подскажите, с какого языка начать изучение программирования с JS или Python? Цель — легче заработать денег, а то в моей отрасле больше чем я зарабатываю очень сложно достичь.