Аналоги в Python и JavaScript. Часть четвертая

Автор оригинала: Aidas Bendoraitis a.k.a. archatas
  • Перевод

Четвертая часть серии статей про аналоги в Python и JavaScript.


В этой части: аргументы функций, создание и работа с классами, наследование, геттеры-сеттеры и свойства класса.


Краткое содержание предыдущих частей:


  1. Часть первая: приведение к типу, тернарный оператор, доступ к свойству по имени свойства, словари, списки, строки, конкатенация строк.
  2. Часть вторая: JSON, регулярки, ошибки-исключения
  3. Часть третья: современные Python и JS: строковые шаблоны (f-строки), распаковка списков, лямбда-функции, итерации по спискам, генераторы, множества.

Аргументы функций


У Питона обширный инструментарий для работы с аргументами функций — есть значения по умолчанию, переменное число позиционных и именованных аргументов (*args и **kwargs).


Когда вы передаете значение в функцию, вы можете указать имя аргумента которому это значение будет передано. В JS тоже существует такая возможность.


Значения по умолчанию для аргументов функций могут быть определены в Питоне:


from pprint import pprint

def report(post_id, reason='not-relevant'):
    pprint({'post_id': post_id, 'reason': reason})

report(42)
report(post_id=24, reason='spam')

В JS аналогично:


function report(post_id, reason='not-relevant') {
    console.log({post_id: post_id, reason: reason});
}

report(42);
report(post_id=24, reason='spam');

Позиционные аргументы в Питоне могут быть обработаны используя оператор *:


from pprint import pprint

def add_tags(post_id, *tags):
    pprint({'post_id': post_id, 'tags': tags})

add_tags(42, 'python', 'javascript', 'django')

В JS обработка позиционных аргументов происходит при помощи оператора ...:


function add_tags(post_id, ...tags) {
    console.log({post_id: post_id, tags: tags});
}

add_tags(42, 'python', 'javascript', 'django');    

Именованные аргументы часто применяются в Питоне когда необходимо передавать изменяемое число аргументов:


from pprint import pprint

def create_post(**options):
    pprint(options)

create_post(
    title='Hello, World!', 
    content='This is our first post.',
    is_published=True,
)
create_post(
    title='Hello again!',
    content='This is our second post.',
)

Передача множества именованных аргументов в JS реализуется с помощью словаря (options в данном примере):


function create_post(options) {
    console.log(options);
}

create_post({
    'title': 'Hello, World!', 
    'content': 'This is our first post.',
    'is_published': true
});
create_post({
    'title': 'Hello again!', 
    'content': 'This is our second post.'
});

Классы и наследование


Питон — объектно-ориентированный язык. JS начиная с ECMAScript 6 также позволяет писать объектно-ориентированный код без всяких уловок и синтаксических оборотов.


Питон. Создаем класс, конструктор и метод для текстового представления объекта:


class Post(object):
    def __init__(self, id, title):
        self.id = id
        self.title = title

    def __str__(self):
        return self.title

post = Post(42, 'Hello, World!')
isinstance(post, Post) == True
print(post)  # Hello, World!

Аналогичные действия на JS:


class Post {
    constructor (id, title) {
        this.id = id;
        this.title = title;
    }
    toString() {
        return this.title;
    }
}

post = new Post(42, 'Hello, World!');
post instanceof Post === true;
console.log(post.toString());  // Hello, World!

Создадим два класса Article и Link в Питоне, которые будут наследоваться от класса Post. Можно заметить, что мы используем функциюsuper для доступа к методам базового класса Post:


class Article(Post):
    def __init__(self, id, title, content):
        super(Article, self).__init__(id, title)
        self.content = content

class Link(Post):
    def __init__(self, id, title, url):
        super(Link, self).__init__(id, title)
        self.url = url

    def __str__(self):
        return '{} ({})'.format(
            super(Link, self).__str__(),
            self.url,
        )

article = Article(1, 'Hello, World!', 'This is my first article.')
link = Link(2, 'DjangoTricks', 'https://djangotricks.blogspot.com')
isinstance(article, Post) == True
isinstance(link, Post) == True
print(link)
# DjangoTricks (https://djangotricks.blogspot.com)

То же самое в JS:


class Article extends Post {
    constructor (id, title, content) {
        super(id, title);
        this.content = content;
    }
}

class Link extends Post {
    constructor (id, title, url) {
        super(id, title);
        this.url = url;
    }
    toString() {
        return super.toString() + ' (' + this.url + ')';
    }
}

article = new Article(1, 'Hello, World!', 'This is my first article.');
link = new Link(2, 'DjangoTricks', 'https://djangotricks.blogspot.com');
article instanceof Post === true;
link instanceof Post === true;
console.log(link.toString());
// DjangoTricks (https://djangotricks.blogspot.com)

Свойства класса: геттеры и сеттеры.


В объектно-ориентированном программировании у классов есть атрибуты, методы и свойства. Свойства — это смесь атрибутов и методов. Вы можете обращаться со свойствами как с атрибутами, но где-то внутри они вызывают специальные методы называемые геттерами и сеттерами (getters/setters) для специфической обработки данных.
В данном примере на Питоне показан базовый способ описания геттера и сеттера для свойства slug с помощью декораторов:


class Post(object):
    def __init__(self, id, title):
        self.id = id
        self.title = title
        self._slug = ''

    @property
    def slug(self):
        return self._slug

    @slug.setter
    def slug(self, value):
        self._slug = value

post = Post(1, 'Hello, World!')
post.slug = 'hello-world'
print(post.slug)

В JS геттер и сеттер для свойства slug могут быть описаны как:


class Post {
    constructor (id, title) {
        this.id = id;
        this.title = title;
        this._slug = '';
    }

    set slug(value) {
        this._slug = value;
    }

    get slug() {
        return this._slug;
    }
}

post = new Post(1, 'Hello, World!');
post.slug = 'hello-world';
console.log(post.slug);

Выводы


  • В обоих языках можно описать дефолтные значения у аргументов функций.
  • В обоих языках можно передавать в функцию произвольное число именованных или позиционных аргументов.
  • Оба языка поддерживают объектно-ориетированную парадигму программирования.

Ну, и напоследок автор оригинального поста предлагает купить у него пдфку с цветными шпаргалками по питону и джаваскрипту за пятнадцать баксов.


Распечатать и повесить на стену или сделать бумажный самолетик — решать вам!

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 6

    0
    Не хватает питоньих дата-классов и прототипного наследования в джаваскрипте, пусть и ссылочкой на мануал
    0
    Не хватает упоминания про метаклассы, про **kwargs для передачи неопределенного набора параметров перекрытому методу через super()
      0
      super() это наверное все таки функция, а не ключевое слово?
        0
        да, спасибо, поправил
        0

        Автор пишет на питоне3, но видимо не в курсе, что
        class Post вполне валидно без (object)
        super() вызывается вот так: super().init(param1, param2)

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

        Самое читаемое