История одной разработки

Хотя прошлая моя публикация была замечена рядом людей, тем не менее она получила клеймо «Перевода». Что без сомнений делает все мои рекомендации, отмеченные там, плагиатом. Ведь не существует единого мнения по ведению кода.

Поэтому, в этот раз, я решил рассказать вам свою историю о том, как я выполнял заказ по разработке странички для интернет магазина.

Возможно, вы скажите, что это довольно заезженная тема. Однако, не всё так просто. Если обычно сложности в работу накидывают сами заказчики, то тут я решил сам себе подыскать кочки. Дело в том, что я довольно давно уже отошёл от разработок простых сайтов, страниц и всяких CMS в пользу Single Page Application. Предложение доработать ряд элементов на странице, которая являлась частью уже готового сайта и имела ряд табу в подходе к разработке, не внушало мне особого интереса. Отмечу, что сама задача не сложная. Суть заключалась в том, чтобы выводить товары в соответствующем виде и со своей внутренней логикой. Так же, немаловажное условие было: лёгкое редактирование контента самим заказчиком. Так как сайт сам по себе разработан ни как SPA, то делать это средствами, мною любимого, Angular я не могу… или нет? Да, мне нельзя было подключать к сайту сам fraemwork, но я мог сделать bundle файл со всеми необходимыми мне условиями выполнения задачи.

Сразу скажу, что конечно существуют способы куда проще и правильнее, но в этом случае, я бы не стал браться за эту работу. Мною двигал интерес, в теории я знал, что это сработает. Я читал о неком CodeMix, компоненте, который поставляется с версии Angular 6 и выше. Знакомьтесь, Angular Elements. В двух словах они преобразуют компоненты в элементы HTML (+ JavaScript), позволяя нам использовать наши компоненты в других приложениях, разных fraemworks (тот же, React) или даже в простой странице HTML + JavaScript!

Я не буду описывать заказной вариант работы и в качестве примера приведу простой компонент панели, который будет отображать заголовок и содержимое под ним сообщение. Так же мы разместим, в рамках заголовка, checkbox для контроля за отображением содержимого сообщения. Затем мы продолжим использовать эту панель на простой HTML-странице. Тем самым решив задачу.

По рецепту нам понадобится:

  • Node.js,
  • Диспетчер пакетов узлов (npm),
  • Angular CLI (> 6.0.0),
  • CodeMix

В Eclipse создаём новый проект.


File > Create > Project > CodeMix > Angular Project

Далее в терминале для проекта (Ctrl+Shift+P)


Вводим: Terminal: Create New Integrated Terminal

Терминал автоматически откроется в папке проекта. В нём мы вписываем npm install, ng serve. После, спокойно переходим на страницу: localhost:4200. Далее нам нужно задействовать модули Angular element и poly-fills для совместимости браузеров, поскольку они не поддерживаются как надо в браузерах от Microsoft.

npm install @angular/elements @webcomponents/custom-elements

Создадим компонент.

Используя незамысловатые возможности Angular CLI, пишем следующее:
ng g c codemix-example

Наш компонент готов, осталось привести его в порядок.

HTML:

<div class="CodemixExampleComponentClass">   <div class="head">     <span>{{ title }}</span>     <input type="checkbox" [checked]="isShow" (change)="changeShow()" />   </div>   <div class="body" *ngIf="isShow">{{ content }}</div> </div>

TypeScript:

import { Component, Input, ViewEncapsulation } from '@angular/core'; @Component({   selector: 'codemix-example',   templateUrl: './codemix-example.component.html',   styleUrls: ['./codemix-example.component.css'],   encapsulation: ViewEncapsulation.Native }) export class CodemixExampleComponent {   public isShow: boolean;   constructor() { }    @Input() public content;   @Input() public title;      public changeShow(): void {     this.isShow = !this.isShow;   } }

В детали CSS я не буду углубляться, для этого примера я просто задал основным блокам свой цвет фона.

Проверяем наш компонент в том что он работает и продолжаем.

//app.module.ts.

import { BrowserModule } from '@angular/platform-browser'; import { NgModule, Injector } from '@angular/core'; import { createCustomElement } from '@angular/elements'; import { CodemixExampleComponent } from './codemix-example/codemix-example.component';  import { AppComponent } from './app.component';  @NgModule({   declarations: [     AppComponent,     CodemixExampleComponent   ],   entryComponents: [CodemixExampleComponent],   imports: [     BrowserModule   ],   providers: [] }) export class AppModule {   constructor(private injector: Injector){ }      ngDoBootstrap(){     const element = createCustomElement(       CodemixExampleComponent, { injector: this.injector }     );     customElements.define('codemix-example', element)   } }

В приведенном выше коде мы остановили Angular от автоматической загрузки приложения. Мы достигли этого, удалив свойство bootstrap в объекте параметра decorator и перезаписав ngDoBootstrap метод в AppModule классе. Мы также добавляем компонент CodemixExampleComponent в массив entryComponents, чтобы инструктировать Angular создавать компонент, даже если он не является частью шаблона. Затем в ngDoBootstrap компонент CodemixExampleComponent анализируется с помощью функции createCustomElement из модуля Angular Elements. Теперь мы можем использовать элемент в HTML-файле в нашем проекте.

Например, index.html файл можно переписать следующим образом:

<!doctype html> ... <body>   <div style="width: 50vw; margin: auto;">     <codemix-example        title="Title text"        content="Content text Content text  Content text Content text Content text Content text Content text Content text Content text Content text">     </codemix-example>   </div> </body> ...

Получение bundle файла

Теперь, когда мы можем использовать элемент в HTML-документе в нашем проекте, следующим шагом будет создание bundle файла для использования его в качестве зависимости страницы.

Для этого нам понадобиться модуль concat:
npm install concat --save-dev

Остаётся создать скрипт сборки в корне папки проекта.

// build.js:

const concat = require('concat'); const files = [    'node_modules/@webcomponents/custom-elements/src/native-shim.js',     './dist/angulartest/runtime.js',     './dist/angulartest/polyfills.js',     './dist/angulartest/main.js' ];  const outputFile = './dist/bundle.js'; concat(files, outputFile);

Финальный штрих, запускаем команду, ну или добавляем её в package.json к объекту scripts:
ng build --prod --output-hashing = none && node build-script.js

В итоге мы получили заветный bundle.js. Файл, который теперь может быть использован в любом месте. Скопируйте этот файл в другое место и создайте простой HTML-файл в той же папке.

Если кому интересно на выходе у меня получилось следующее:

А вот и простейший index.html

<!doctype html> <html lang="en"> <head>   <meta charset="utf-8">   <title>Angulartest</title> </head> <body>   <div style="width: 50vw; margin: auto;">     <codemix-example        title="Title text"        content="Content text Content text  Content text Content text Content text Content text Content text Content text Content text Content text">     </codemix-example>   </div> <script type="text/javascript" src="bundle.js"></script> </body> </html>

Заключение

Как вы видите, мы просто использовали Angular компонент в простом HTML-файле. Да, здорово, что даже в таких задачах Angular способен о себе заявить. Мы способны использовать наш компонент, разработанный на Angular, в React, Vue и т.д., ну не круто ли? Но, как я и сказал в начале, это не единственный и точно не лучший вариант в той задаче, что решал я. Я сделал это только потому что мне было интересно сделать так. Важно знать, что такой способ не полностью поддерживается большинством браузеров. А так же вынуждает нас работать с файлом, который довольно большой для работы с всего лишь одним элементом. Например мой получился в 234КБ.


ссылка на оригинал статьи https://habr.com/post/427075/

Добыча данных из Твиттера

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

Предлагаю угадать, какую технологию обрамляет это облако слов?

Облако

Используя Твиттер API можно извлекать и анализировать самую разнообразную информацию. Статья о том, как это осуществить с помощью языка программирования R.

Написание кода занимает не так уж много времени, сложности могут возникнуть из-за изменений и ужесточения Твиттер API, судя по всему компания всерьез озаботилась вопросами безопасности после выволочки в Конгрессе США по следам расследования влияния «русских хакеров» на выборы в США в 2016 г.

Получение доступа к API

Зачем кому-то может понадобиться извлекать в промышленных масштабах данные из Твиттер? Ну например это помогает делать более точные прогнозы относительно исхода спортивных событий. Но я уверен, что есть и другие пользовательские сценарии.

Для начала понятно, что нужно иметь учетную запись Твиттер с указанием номера телефона. Это необходимо для создания приложения, именно этот шаг дает доступ к API.

Заходим на страницу разработчика и жмем на кнопку Create an app. Далее следует страничка на которой надо заполнить информацию о приложении. На данный момент страница состоит из следующих полей.

apps

  • AppName — имя приложения (обязательно).
  • Application description — описание приложения (обязательно).
  • Website URL — страница сайта приложения (обязательно), можно вписать все, что угодно похожее на URL.
  • Enable Sign in with Twitter (check box) — Вход со страницы приложения на Твиттер, можно попустить.
  • Callback URLs — Обратная вызов приложения при аутентификации (обязательно) и необходимо, можно оставить http://127.0.0.1:1410.

Далее следуют необязательные к заполнению поля: адрес страницы условий предоставления услуг, имя организации и проч.

При создании учетной записи разработчика следует выбрать один из трех возможных вариантов.

  • Standard — Базовый вариант, можно искать записи на глубину ≤ 7 дней, бесплатный.
  • Premium — Более продвинутый вариант, можно искать записи на глубину ≤ 30 дней и с 2006 г. Бесплатный, но дают не сразу по рассмотрению заявки.
  • Enterprise — Бизнес-класс, платный и надежный тариф.

Я выбрал Premium, ждать одобрения пришлось около недели. Не могу сказать всем-ли подряд дают его, но попытаться стоит в любом случае, а Standard никуда не денется.

Подключение к Твиттеру

После того, как вы создали приложение в закладке Keys and tokens появится набор содержащий следующие элементы. Ниже названия и соответствующие переменные R.

Consumer API keys

  • API keyapi_key
  • API secret keyapi_secret

Access token & access token secret

  • Access tokenaccess_token
  • Access token secretaccess_token_secret

Устанавливаем необходимые пакеты.

install.packages("rtweet") install.packages("tm") install.packages("wordcloud")

Эта часть кода будет выглядеть следующим образом.

library("rtweet") api_key <- "" api_secret <- "" access_token <- "" access_token_secret <- "" appname="" setup_twitter_oauth (   api_key,   api_secret,   access_token,   access_token_secret)

После аутентификации R предложит сохранить коды OAuth на диске, для последующего использования.

[1] "Using direct authentication" Use a local file to cache OAuth access credentials between R sessions? 1: Yes 2: No

Оба варианта приемлемы, я выбрал 1-й.

Поиск и фильтрация результатов

tweets <- search_tweets("hadoop", include_rts=FALSE, n=600)

Ключ include_rts позволяет контролировать включение в поиск, или исключение из него ретвитов. На выходе получаем таблицу с множеством полей, в которых есть подробности и детали каждой записи. Вот первые 20.

> head(names(tweets), n=20)  [1] "user_id"              "status_id"            "created_at"  [4] "screen_name"          "text"                 "source"  [7] "display_text_width"   "reply_to_status_id"   "reply_to_user_id" [10] "reply_to_screen_name" "is_quote"             "is_retweet" [13] "favorite_count"       "retweet_count"        "hashtags" [16] "symbols"              "urls_url"             "urls_t.co" [19] "urls_expanded_url"    "media_url"

Можно составить более сложную строку поиска.

search_string <- paste0(c("data mining","#bigdata"),collapse = "+") search_tweets(search_string, include_rts=FALSE, n=100)

Результаты поиска можно сохранить в текстовом файле.

write.table(tweets$text, file="datamine.txt")

Сливаем в корпус текстов, производим фильтрацию от служебных слов, знаков пунктуации и переводим все в нижний регистр.

Существует еще одна функция поиска — searchTwitter, для которой требуется библиотека twitteR. В чем-то она удобнее search_tweets, а в чем-то ей уступает.

Плюс — наличие фильтра по времени.

  tweets <- searchTwitter("hadoop", since="2017-09-01", n=500)   text = sapply(tweets, function(x) x$getText())

Минус — вывод не таблица, а объект типа status. Для того, чтобы его использовать в нашем примере нужно из вывода вычленить текстовое поле. Это и делает sapply во второй строке.

corpus <- Corpus(VectorSource(tweets$text))   clearCorpus <- tm_map(corpus, function(x) iconv(enc2utf8(x), sub = "byte"))  tdm <- TermDocumentMatrix(clearCorpus, control =     list(removePunctuation = TRUE,         stopwords = c("com", "https", "hadoop", stopwords("english")),         removeNumbers = TRUE,         tolower = TRUE))

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

Построение облака слов

Облака слов впервые появились на фото-хостинге Фликр, насколько мне известно и с тех пор обрели популярность. Для этой задачи нам понадобится библиотека wordcloud.

m <- as.matrix(tdm) word_freqs <- sort(rowSums(m), decreasing=TRUE) dm <- data.frame(word=names(word_freqs), freq=word_freqs)  wordcloud(dm$word, dm$freq, scale=c(3, .5), random.order=FALSE, colors=brewer.pal(8, "Dark2"))

Функция search_string позволяет задать в качестве параметра язык.

search_tweets(search_string, include_rts=FALSE, n=100, lang="ru")

Однако ввиду того, что NLP пакет для R плохо русифицирован, в частности нет списка служебных, или стоп-слов, построение облака слов с поиском на русском у меня не получилось. Буду рад, если в комментариях найдут лучшее решение.

Ну, и собственно…

скрипт целиком

library("rtweet") library("tm") library("wordcloud")  api_key <- "" api_secret <- "" access_token <- "" access_token_secret <- "" appname="" setup_twitter_oauth (   api_key,   api_secret,   access_token,   access_token_secret)  oauth_callback <- "http://127.0.0.1:1410" setup_twitter_oauth (api_key, api_secret, access_token, access_token_secret) appname="my_app"  twitter_token <- create_token(app = appname, consumer_key = api_key, consumer_secret = api_secret) tweets <- search_tweets("devops", include_rts=FALSE, n=600)  corpus <- Corpus(VectorSource(tweets$text)) clearCorpus <- tm_map(corpus, function(x) iconv(enc2utf8(x), sub = "byte"))  tdm <- TermDocumentMatrix(clearCorpus, control =     list(removePunctuation = TRUE,         stopwords = c("com", "https", "drupal", stopwords("english")),         removeNumbers = TRUE,         tolower = TRUE))  m <- as.matrix(tdm) word_freqs <- sort(rowSums(m), decreasing=TRUE) dm <- data.frame(word=names(word_freqs), freq=word_freqs)  wordcloud(dm$word, dm$freq, scale=c(3, .5), random.order=FALSE, colors=brewer.pal(8, "Dark2"))

Использованные материалы.

Краткие ссылки:

Оригинальные ссылки:

https://stats.seandolinar.com/collecting-twitter-data-getting-started/
https://opensourceforu.com/2018/07/using-r-to-mine-and-analyse-popular-sentiments/
http://dkhramov.dp.ua/images/edu/Stu.WebMining/ch17_twitter.pdf
http://opensourceforu.com/2018/02/explore-twitter-data-using-r/
https://cran.r-project.org/web/packages/tm/vignettes/tm.pdf

P. S. Подсказка, ключевое слово облака на КДПВ не используется в программе, оно связано с моей предыдущей статьей.


ссылка на оригинал статьи https://habr.com/post/426657/

Локальный NPM репозиторий за 5 минут со своими пакетами и кэширование

Доброго времени суток!

Рано или поздно в организациях возникают проблемы с распространением js модулей между проектами, настало то время когда в нашей компании встал этот вопрос.

Копировать и вставлять код это путь на темную сторону, поэтому было принято решение писать не просто js код, а создавать из него npm пакеты чтобы распространять между своими проектами.

Поиск бесплатных, частных npm репозиториев завел в тупик, а использование частных репозиториев на npm требует платы (а это не наш менталитет).

Поскольку в офисе есть сервер, который работает всегда(почти), было решено развернуть локальный npm.

Устройство популярных локальных npm репозиториев достаточно простое и однообразное, мы выбрали Verdaccio, из-за того, что обновления для него публиковались сравнительно недавно.

В основном это npm пакет, который ставится на Node.js > 4 и предоставляет веб интерфейс на определенный порт.

Огромным плюсом является функция кеширования, когда локальный npm не находит запрошенный у него пакет, то он идет на npmjs.com, скачивает к себе на диск нужный пакет и при повторных запросах этого пакета раздает его уже кешированную версию.

Итак, к настройке.

На машине, которая будет сервером:

npm i -g verdaccio 

В файле C:\Users\lab\AppData\Roaming\verdaccio\config.yaml находятся параметры сервера

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

listen: 192.168.51.79:1234 

192.168.51.79 это ip сервера, задав адрес таким образом мы сможем обращаться из локальной сети по ip сервера, либо по его DNS имени и добавив порт 1234 мы будем попадать на web интерфейс.

Если прописать listen: 192.168.51.79:80 то писать порт при настройках клиентов необязательно.

Далее запускаем наш локальный npm

verdaccio 

Остальные действия будем производить на клиентах.

Устанавливаем путь к локальному репозиторию.

npm set registry http://192.168.51.79:1234 

Готово, теперь все Ваши npm запросы будут идти и кешироваться через локальный сервер.

Если Вам нужно опубликовать npm пакет на сервер, то выполняем следующую инструкцию.

Cоздаем пользователя

npm adduser --registry http://192.168.51.79:1234  login password mail@mail.ru 

Логинимся

npm login password bezrukov@mir-omsk.ru 

Проверяем, что мы под пользователем «login»

npm whoami 

Публикуем пакет, rootProjectFolder — это папка с минимум тремя файлами index.js \ package.json \ README.md, пример выложил на github.

cd /rootProjectFolder npm publish 

Обновляем пакет. Обновляем версию в package.json, выполняем команды

cd /rootProjectFolder npm publish 

Пакет на локальном сервере, можно перейти на 192.168.51.79:1234 и посмотреть, что там появился новый пакет.

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

image

P.S.: Если Вы ваша сеть имеет прокси, то на сервере нужно явно указать ее параметры, а на клиенте этого делать не нужно, потому что npm репозиторий локальный и для доступа клиентов к серверу прокси не требуется.

На сервере надо выполнить команду npm config edit и добавить следующие строчки

proxy=http://name:pass@proxy:port/ https-proxy=http://name:pass@proxy:port/ registry=http://registry.npmjs.org/ 

Буду рад комментариям и отзывам о том, как это устроено у вас.


ссылка на оригинал статьи https://habr.com/post/427069/

Генерал Авайлабилити PostgreSQL 11

Специальный выпуск POSTGRESSO, посвященный выходу официального релиза версии 11.


На улице PostgreSQL праздник. После четырех beta вышла PostgreSQL 11 General Availability, то есть официальная версия. В анонсе есть даже приветственное слово Брюса Момжана: «готовя этот релиз, сообщество особенно заботилось о добавлении функциональности, необходимой для работы с очень большими базами данных. Доказано, что PostgreSQL хорошо работает с транзакционными нагрузками, а теперь новая версия — PostgreSQL 11 — облегчит разработчикам еще и создание приложений для Big Data».

В release notes выделяют

  • секционирование:
    • добавлено секционирование по хешу;
    • PRIMARY KEY, FOREIGN KEY, индексы (см. ниже на эту тему) и триггеры;
    • секция по умолчанию для записей, вышедших за границы созданных секций;
    • UPDATE по ключу секционирования теперь может автоматически перемещать запись в соответствующую секцию;
    • PostgreSQL научился исключать ненужные секции (partition pruning) во время исполнения запросов SELECT;
  • распараллеливание:
    • теперь можно параллельно создавать индекс в случае B-tree;
    • при CREATE TABLE… AS, CREATE MATERIALIZED VIEW и в некоторых случаях запросов с UNION;
    • улучшена производительность в параллельных HASH JOIN и SEQUENTIAL SCAN;
  • появились хранимые процедуры, и в них возможно управление транзакциями;
  • JIT-компиляция некоторых запросов, выигрыш на вычислении выражений;
  • оконные функции теперь поддерживают все фреймовые опции SQL:2011 стандарта, в том числе расстояния по RANGE у PRECEDING/FOLLOWING, режим GROUPS, возможность исключения строк из фрейма;
  • появились покрывающие индексы [не покрывающие, а инклюзивные, строго говоря — прим. POSTGRESSO], использующие выражение INCLUDE при CREATE INDEX;
  • из раздела «разное»: ALTER TABLE… ADD COLUMN c значениями NOT NULL по умолчанию: этот вариант команды теперь не перезаписывает все строки таблицы и, следовательно, работает быстро.


Впечатляющий список, хотя и не сенсационный: по определению Feature freeze фиксирует функциональность, а было это еще в середине апреля.

Постгресисты из HPE регулярно публикуют детальную сводку функциональности. После апрельской Feature freeze она была такова (в этом PDF есть и краткая сводка новшеств, и детали, и примеры).

Не совсем понятны, все же, сверхбурные восторги (см. ниже реакцию Лукаса Фитла) по поводу этой версии. Сделано очень много полезного, но доделывать еще предстоит очень важные вещи, а есть направления по которым не то чтобы конь не валялся, но это лишь свет в начале тоннеля. Например, многое доделали в секционировании, спору нет, но до сих пор невозможно сослаться на секционированную таблицу при помощи FOREIGN KEY. Можно создать FOREIGN KEY, но в самой секционированной таблице. Глобальных индексов нет.

JIT/LLVM появился, но тут же исчез из дефолтной конфигурации: по умолчанию он выключен. И это неспроста, ведь в некоторых случаях он не ускоряет, а вносит ненужные оверхеды.

Не вошли в новую версию большие патчи с функциями для работы с JSON/JSONB.

За подключаемыми движками хранения (pluggable storage) и, в том числе, zheap (то есть Oracle-подобный UNDO, работающий без VACUUM) многие следят с замиранием сердца. Они в эмбриональном состоянии, не утрясли еще даже API. Обзор возможностей в этом направлении есть здесь.

Но это было лишь напоминание о том, что еще предстоит. Работа над новым и недоделанным старым идёт вовсю, направление развития понятно.

Статьи

New in Postgres 11: Monitoring JIT performance, Auto Prewarm & Stored Procedures
Лукас Фитл (Lukas Fittl) не только перечисляет важнейшие новшества, но и приводит оценки производительности, листинги, планы. Лукас поясняет, что нового в расширении для предразогрева базы (pg_prewarm), напоминает об особенностях хранимых процедур, тестирует JIT. Вывод ультраоптимистический: похоже, это будет лучший релиз PostgreSQL.

Postgres 11 — a First Look
Крейг Кирстинс (Craig Kerstiens) обращает внимание в том числе на фичи, не расписанные выше, напоминает об изменениях в статистике, например. Или о… см. ниже.

Adding new table columns with default values in PostgreSQL 11
Статья о любопытном патче автора, Эндрю Данстэна (Andrew Dunstan) из 2ndQuadrant. Теперь, например, в столбце по умолчанию могут задаваться не только статические величины, но и CURRENT_TIMESTAMP или random().

На конференциях и на вебинарах на тему PostgreSQL 11

Питер Айзентраут (Peter Eisentraut) из 2ndQuadrant провёл вебинар по новшествам PostgreSQL 11. Запись дополнена ответами на вопросы, неотвеченные на вебинаре.

На PGCONF.EU в Лиссабоне (вот программа) запланирован, конечно, обзорный доклад: Магнуса Хагандера (Magnus Hagander)
What’s new in PostgreSQL 11? и к нему парой
What is old in PostgreSQL 11? Деврима Гюндюца (Devrim Gündüz).
Towards more efficient query plans: PostgreSQL 11 and beyond Александра Кузьменкова (Postgres Professional), в котором будут упомянуты не только (и даже не столько) закоммиченные фичи, сколько то, что еще в работе.
Также в программе есть и доклады
PostgreSQL worst practices Ильи Космодемьянского (Data Egret)
Do you need a Full-Text Search in PostgreSQL ? Олега Бартунова (Postgres Professional),
Advanced PostgreSQL Backup and Recovery methods Анастасии Лубенниковой (Postgres Professional)


Подписывайтесь на канал postgresso!

Идеи и пожелания присылайте на почту: news_channel@postgrespro.ru
Предыдущие выпуски: #10, #9, #8, #7, #6, #5, #4, #3, #2, #1


ссылка на оригинал статьи https://habr.com/company/postgrespro/blog/426745/

Метаморфозы атрибутов класса

Короткая заметка из серии «Вас предупреждали»
Переход с классических языков программирования на Питон доставляет немало сюрпризов.
Читаем документацию:

Generally speaking, instance variables are for data unique to each instance and class variables are for attributes and methods shared by all instances of the class

Попробуем поиграться

class Vessel:     #class attribute     vtype = "boat"      #instance attribute     def __init__(self, name):         self.name = name 


Создаем два объекта проверим значения всех атрибутов:

Iowa = Vessel("Iowa") Drum=Vessel("Drum") printAttr(Iowa, Drum)  >>name=Iowa          	vtype=boat          	__class__.vtype=boat          	 >>name=Drum          	vtype=boat          	__class__.vtype=boat  

Пока все как и ожидалось.
Попытаемся изменить vtype: это можно сделать двумя способами, которые по сути просто разный синтаксис одного и того же

Vessel.vtype = "USS boat" printAttr(Iowa, Drum) >>name=Iowa          	vtype=USS boat      	__class__.vtype=USS boat      	 >>name=Drum          	vtype=USS boat      	__class__.vtype=USS boat      	  Iowa.__class__.vtype = 'USS WW2 Boat' printAttr(Iowa, Drum) >>name=Iowa          	vtype=USS WW2 Boat  	__class__.vtype=USS WW2 Boat  	 >>name=Drum          	vtype=USS WW2 Boat  	__class__.vtype=USS WW2 Boat  	 

И снова все в порядке.
Теперь попытаемся сделать тоже самое через атрибут объекта.

Drum.vtype = 'submarine' printAttr(Iowa, Drum) >>name=Iowa          	vtype=USS WW2 Boat  	__class__.vtype=USS WW2 Boat  	 >>name=Drum          	vtype=submarine     	__class__.vtype=USS WW2 Boat  	 

И вот первая неожиданность: несмотря на то, что vtype это атрибут класса, неожиданно он становится атрибутом объекта.
Проверим:

Vessel.vtype = "NAVY Museum" >>name=Iowa          	vtype=NAVY Museum   	__class__.vtype=NAVY Museum   	 >>name=Drum          	vtype=submarine     	__class__.vtype=NAVY Museum   	 

а что если…

 del Drum.vtype >>name=Iowa          	vtype=NAVY Museum   	__class__.vtype=NAVY Museum   	 >>name=Drum          	vtype=NAVY Museum   	__class__.vtype=NAVY Museum    

И снова атрибут класса.
Следующее выражение уже не проходит

del Drum.vtype printAttr(Iowa, Drum) 	del Drum.vtype 	AttributeError: vtype 

И последний пример, эмулирующий переопределения класса и удаление атрибута vtype.

Drum.vtype = 'submarine' del Vessel.vtype printAttr(Iowa, Drum)  >>name=Iowa          	 >>name=Drum          	vtype=submarine     	 

Если начать разбираться с namespace-ами, то подобное поведение становится понятным.
Однако для программистов, кто раньше работал с нормальными языками, это по меньшей мере кажется странным. А если говорить о больших проектах, которые поддерживаются несколькими поколениями разработчиков, это может оказаться провалом сроков и пр.
Принимая во внимание концепцию Питона, что все открыто для всех, почему бы не сделать доступ к «классным» атрибутам только через __class__ или его аналог. На мой взгляд, это бы хоть как-то оградило от сюрпризов и заставило 10 раз подумать прежде чем присваивать что-то классным атрибутам на уровне объектов.


ссылка на оригинал статьи https://habr.com/post/427065/