LINUX.ORG.RU
ФорумTalks

Ненависть: не люблю Python

 ,


1

4

Как люди программируют на этом языке? ППЦ

По роду деятельности приходится изучать это и после Perl такая тоска накатывает шоппц.

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

Например есть у меня скрипт «если курсор мыши в правом верхнем углу экрана, то не давать включать screensaver».

В нем есть такой вот блок, определяющий подключенные мониторы и их конфиг:

#!/usr/bin/perl

use 5.20.0;
use YAML;

my %list;
open my $fh, '-|', '/usr/bin/xrandr';
while(<$fh>) {
    if (/^(\S+)\sconnected\s+(primary\s+)?(\d+)x(\d+)([+-]\d+)([+-]\d+)/) {
        $list{$1} = {
            name        => $1,
            w           => $3,
            h           => $4,
            x           => int($5),
            y           => int($6),
            primary     => $2 ? 1 : 0
        }
    }
}

print YAML::Dump \%list;

Запускаем - рассказывает о подключенных мониторах в машиночитаемом виде:

---
DP-1:
  h: 1440
  name: DP-1
  primary: 0
  w: 2560
  x: 2560
  y: 0
DP-2-1:
  h: 1440
  name: DP-2-1
  primary: 0
  w: 2560
  x: 0
  y: 0
eDP-1:
  h: 1080
  name: eDP-1
  primary: 1
  w: 1920
  x: 1280
  y: 1440

вроде что может быть проще?

Однако пытаемся переписать это на python и натыкаемся:

  1. что open - не умеет работать с пайпами
  2. что про пайпы велосипедят 100500 модулей
  3. что у строк есть 100500 методов, но работа с регекспами вынесена в какой-то ужасно сдизайненный модуль `re`
  4. что эти 20 строк кода на Python превратятся в 200

и как вы с этим живете, мозахисты?

★★

Ответ на: комментарий от Darth_Revan

Слегка переписал, попытавшись сделать более похожим на то

в чем фича: у меня код одинаково будет работать хоть xrandr выдаст 20 строк, хоть 20 тыс.

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

вот эти хрени так вообще убивают

  • universal_newlines=True
  • re.MULTILINE
  • default_flow_style=False
  • end=«»

типовая же Unix-операция: запустить внешнюю прогу и пропустить ее вывод через себя.

понятно почему выше написали «найти библиотеку и на ней сделать» - это потому что простые вещи в Python делать сложно: 29 методов у класса string, а поиска по регекспу нет. кабздец

rsync ★★
() автор топика

А еще оно несовместимо само с собой

Установил pydoc

шелл комплитит:

pydoc     pydoc2.7  pydoc3    pydoc3.6

Далее

pydoc yaml

говорит не знаю мол такого

а

pydoc3 yaml

показывает доку.

Вопрос: на кой держать N версий python в ситеме?

Ответ: потому что НАДО ПЕРЕПИСЫВАТЬ АБСОЛЮТНО ВСЁ при переходе на новую версию. И это занимает много времени.

rsync ★★
() автор топика
Ответ на: комментарий от rsync

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

Если нужно обязательно по мере вывода парсить, то тогда вот:

#!/usr/bin/env python3
import re
import subprocess
import sys
import yaml

out = {}
proc = subprocess.Popen(["xrandr"],
                        stdout=subprocess.PIPE, universal_newlines=True)
for line in proc.stdout:
    res = re.match(
            r"(\S+)\sconnected\s+(primary\s+)?(\d+)x(\d+)([+-]\d+)([+-]\d+)",
            line)
    if res:
        out[res[1]] = {
            "name"    : res[1],
            "w"       : int(res[3]),
            "h"       : int(res[4]),
            "x"       : int(res[5]),
            "y"       : int(res[6]),
            "primary" : 1 if res[2] else 0,
        }

yaml.dump(out, sys.stdout, default_flow_style=False)

Darth_Revan ★★★★★
()
Последнее исправление: Darth_Revan (всего исправлений: 1)
Ответ на: комментарий от rsync

типовая же Unix-операция: запустить внешнюю прогу и пропустить ее вывод через себя.

А в shell это делается вообще на раз-два. Идеальный язык.

а поиска по регекспу нет. кабздец

re – это, к слову, «батарейка».
То, что это модули, а не внутренняя логика языка… ну, на них мир не сошёлся.

вот эти хрени так вообще убивают

Опциональные аргументы-то? Ну да, как страшно жить.

Darth_Revan ★★★★★
()
Ответ на: комментарий от nvidia

Вообще по-хорошему это можно делать дергая напрямую xlib, или другие библиотеки в зависимости от задачи.

или другие библиотеки

#!/usr/bin/env python3
import gi
import sys
import yaml
gi.require_version("Gdk", "3.0")
from gi.repository import GLib, Gdk

def on_activate(loop):
    try:
        out = {}
        dpy = Gdk.Display.get_default()
        for m in [dpy.get_monitor(i) for i in range(0, dpy.get_n_monitors())]:
            geom = m.get_geometry()
            out[m.get_model()] = {
                "name"    : m.get_model(),
                "w"       : geom.width,
                "h"       : geom.height,
                "x"       : geom.x,
                "y"       : geom.y,
                "scale"   : m.get_scale_factor(),
                "primary" : 1 if m.is_primary() else 0,
            }
        yaml.dump(out, sys.stdout, default_flow_style=False)
    finally:
        loop.quit()

loop = GLib.MainLoop()
GLib.idle_add(on_activate, loop)
loop.run()

Мне не стыдно.

Darth_Revan ★★★★★
()

Какой гонор! Какое ЧСВ! Какая некомпетентность!

Да это же сферический неофит %название чего угодно% в вакууме!

itn ★★★
()
Ответ на: комментарий от Darth_Revan

Ну и Qt до кучи:

#!/usr/bin/env python3
import sys
import yaml
from PySide2 import QtCore, QtGui

def on_activate(app):
    try:
        out = {}
        for screen in app.screens():
            geom = screen.virtualGeometry()
            out[screen.name()] = {
                "name"    : screen.name(),
                "w"       : geom.width(),
                "h"       : geom.height(),
                "x"       : geom.x(),
                "y"       : geom.y(),
                "primary" : 1 if screen is app.primaryScreen() else 0,
            }
        yaml.dump(out, sys.stdout, default_flow_style=False)
    finally:
        app.quit()

app = QtGui.QGuiApplication(sys.argv)
QtCore.QTimer.singleShot(0, lambda: on_activate(app))
sys.exit(app.exec_())
Всё ещё не стыдно.

Darth_Revan ★★★★★
()
Последнее исправление: Darth_Revan (всего исправлений: 2)
Ответ на: комментарий от pawnhearts

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

eternal_sorrow ★★★★★
()
Ответ на: комментарий от itn

я язык этот разглядываю (даже пока не изучаю) всего пару часов. и вижу что это не язык, а мусор.

  • почему для одинаковых задач - разные библиотеки искать (файлы - open, дочки с пайпами - либа)?
  • почему на три десятка методов класса string ни одного поиска по регекспу?
  • почему в re библиотеке все построено по схеме «сохрани во временную переменную и потом поищи ответ» (заточенность под многострочный код)

почему почему почему...

треш. мусор. systemd

rsync ★★
() автор топика
Последнее исправление: rsync (всего исправлений: 1)
Ответ на: комментарий от eternal_sorrow

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

средствами модуля string этот простейший парсинг будет решаться очень сложно

rsync ★★
() автор топика
Ответ на: комментарий от rsync

да да, для мелкого юзерского скрипта давайте притащим зависимость на Qt и сам Qt.

Сделал для забавы, так сразу критика %).
Впрочем, у такого подхода есть одно преимущество: поддержка не одного только X11 ;-).

Darth_Revan ★★★★★
()
Ответ на: А еще оно несовместимо само с собой от rsync

Далее

pydoc yaml
говорит не знаю мол такого

а

pydoc3 yaml
показывает доку.

Может это потому, что у тебя для третьего питона установлена либа yaml, а для второго нет? Ты напоминаешь, слепого котёнка: тычешься во все стороны и не можешь найти мамкиной титьки, и поэтому орёшь. С чего ты взял, что если тыкнешь пальцем наугад, то попадешь куда надо?

Вопрос: на кой держать N версий python в ситеме?

Не держи. ЕМНИП, крупные дистры уже давно переехали на третий.

Virtuos86 ★★★★★
()
Ответ на: комментарий от eternal_sorrow

Человек на машине времени прилетел, а вы его сразу «УБИВАТ».

Darth_Revan ★★★★★
()

ну что ж, резюмируя, можно сказать, что вброс удался

eternal_sorrow ★★★★★
()

Забирай двоечник и не позорься в следующий раз. «Двести строк» у него...

import subprocess
import re
import yaml


RGX = re.compile(r'^(\S+)\sconnected\s+(primary\s+)?(\d+)x(\d+)([+-]\d+)([+-]\d+)')

res = {}

for r in filter(lambda x: x, [re.match(RGX, s) for s in subprocess.getoutput('/usr/bin/xrandr').split('\n')]):
    r = r.groups()
    res[r[0]] = {'name': r[0], 'w': int(r[2]), 'h': int(r[3]), 'x': int(r[4]), 'y': int(r[5]), 'primary': int(bool(r[1]))}


print(yaml.dump(res, default_flow_style = False).replace('\n- ', '\n\n- '))
DVI-I-1:
  h: 1080
  name: DVI-I-1
  primary: 1
  w: 1920
  x: 1920
  y: 0
VGA-2:
  h: 1080
  name: VGA-2
  primary: 0
  w: 1920
  x: 0
  y: 0
k0valenk0_igor ★★★
()

По роду деятельности приходится изучать это и после Perl такая тоска накатывает шоппц

Тоже осваивал Python после Perl, только по собственной воле.

Твой код в питоне - те же 20 строк, транслируется 1 в 1:

#!/usr/bin/env python3

from subprocess import Popen, PIPE
import yaml
import re

modes = {}
xrandr = Popen('xrandr', encoding='utf-8', stdout=PIPE)
for line in xrandr.stdout:
    match = re.match('(\S+)\sconnected\s+(primary\s+)?(\d+)x(\d+)([+-]\d+)([+-]\d+)', line)
    if match:
        modes[match[1]] = {
            'name': match[1],
            'w': match[3],
            'h': match[4],
            'x': int(match[5]),
            'y': int(match[6]),
            'primary': 1 if match[2] else 0,
        }

print(yaml.dump(modes))

что open - не умеет работать с пайпами
но работа с регекспами вынесена в какой-то ужасно сдизайненный модуль `re`

Тоже это не очень нравилось по первости. Потом стало понятно что это вкусовщина и эффект утёнка, и у питоновского подхода есть свои плюсы. re, в частности, располагает к тому чтобы заранее скомпилировать регулярки и тем сильно ускорить скрипт, интерфейс позволяет не писать в каждой регулярке ^, и с явными match objects удобнее работать когда работаешь с несколькими регулярками сразу. А с Popen, как видно из интерфейса, можно работать со всеми тремя потоками сразу.

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

slovazap ★★★★★
()
Ответ на: комментарий от Rupricht

Порт на Python 3:

#!/usr/bin/python3

import re
from subprocess import Popen, PIPE

randr=Popen("/usr/bin/xrandr",stdout=PIPE)
randr.wait()
for line in randr.stdout.readlines():
 match=re.match(r"^(\S+)\sconnected\s+(primary\s+)?(\d+)x(\d+)([+-]\d+)([+-]\d+)", line.decode('utf-8'))
 if match:
  p=match.groups()
  print ("%s\n\tname: %s\n\tw: %s\n\th: %s\n\tx: %d\n\ty: %d\n\tprimary: %d\n" %(p[0],p[0],p[2],p[3],int(p[4]),int(p[5]),1 if p[1] else 0 ))

saahriktu ★★★★★
()
Ответ на: комментарий от rsync

10000 строк кода там где на перле одна

Тоже к перлу подходит

Siado ★★★★★
()

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

xrandr | sed -re '
/^([^\s]+)\sconnected\s+(primary)?\s*([0-9]+)x([0-9]+)([-+][0-9]+)([-+][0-9]+).*/ ! d
s//\1:\n  name: \1\n  w: \3\n  h: \4\n  x: \5\n  y: \6\n  \2: 1/
s/\n  : 1$/\n  primary: 0/
'
2. таки используем даденое там гвидом, тихо завидуя хаскелистам
import re
from subprocess import Popen,PIPE
from sys import stdout
from operator import truth
import yaml

types=dict(name=str, primary=truth)
regex = r"(?P<name>\S+)\sconnected\s+(?:(?P<primary>primary)\s)?(?P<w>\d+)x(?P<h>\d+)(?P<x>[-+]\d+)(?P<y>[-+]\d+)"
match = re.compile(regex).match
randr = Popen(["xrandr"],stdout=PIPE)
matches = ( match(line) for line in randr.stdout )
dicts = ( m.groupdict() for m in matches if m is not None )
typed = [dict((k,types.get(k,int)(v)) for k,v in i.items()) for i in dicts]
yaml.dump(typed,stdout,default_flow_style=False)

Как видим, питон всего лишь требует импортить кучулиб(наверное можно решить каким-нибудь PYTHONSTARTUPом), и обзывать промежуточные результаты (что не так уж мешает читабельности)

DonkeyHot ★★★★★
()
Ответ на: комментарий от Darth_Revan

Компиляция регулярного выражения в Python не обязательна и существует только для пущей скорости – чтобы в каком-нибудь цикле выражение компилировалось только один раз.

А почему они это просто не автоматизировали, чтобы при повторном использовании выражения оно уже использовалось скомпилированное в предыдущий раз? Зачем эта ручная компиляция? В каком нибудь PHP это разве не так работает?

Deleted
()

Господи какой уродливый код... На Python это все в сто раз удобнее...

demrnd
()
Ответ на: комментарий от grem

Я тоже офигел. что за код? Это кажется код для запуска ядерных ракет в фалауте? Не?

demrnd
()
Ответ на: комментарий от eternal_sorrow

Ну не знаю. Я, например, использовал очень простую регулярку в питоне для определения компонентного состава (количества атомов каждого элемента в соединении) элементов в на основе словаря «хим. элемент : атомных масс». И это мне в данном случае показалось проще, чем просто разделять строку. До этого был некоторый вариант на VBA и OpenOffice.BASIC, где строка дробилась на основе поиска элементов и чисел после них, если они есть. В данном случае скорее исключение, так как регулярки до этого я предпочитал не использовать, несмотря на то, что для всяких разборчиво он, наверное, удобнее (но я через неделю не вспомню, что это за набор символов).

grem ★★★★★
()
Ответ на: комментарий от rsync

Не изучай. Зачем над собой издеваться?

Наверное со мной что-то не то, раз если мне нужно в какой-то степени изучить язык, то я просто его учу, а не жалуюсь, «как в нём всё плохо, неудобно и не так как я привык».

grem ★★★★★
()
Ответ на: комментарий от saahriktu

Здесь должен был быть порт на freepascal, а после этого на gambas. Жаль, что на последний ссылки на доки и книги были нерабочие, когда я их тыкал :(

grem ★★★★★
()
Ответ на: комментарий от env

Но ведь твоя писулька точно так же обосрётся при попытке запуска на perl6

Perl6 это не Perl. вообще другой язык.

мне очень не нравится что эту Java-like поделку называют Perl6. Думаю оно сдохнет не родившись, кстати

rsync ★★
() автор топика
Ответ на: комментарий от rsync

крупные дистры уже давно переехали на третий.

Debian не крупный? а кто тогда крупный?

Какой именно Debian? Надеюсь, не стэйбл?

Virtuos86 ★★★★★
()
Ответ на: комментарий от Virtuos86

Надеюсь, не стэйбл?

именно стейбл. ему всего год.

но кстати когда через год выйдет новый стейбл, уверен что python2.7 в нем еще будет присутствовать ибо всё к тому времени не перепишут

rsync ★★
() автор топика
Ответ на: комментарий от Darth_Revan

это неправильный пример, вот правильный:

$ apt-cache rdepends python2.7|wc -l 
292

я вот одного не понимаю: почему нельзя поддерживать обратную совместимость?

perl 5.28 отлично работает с кодом perl 4

rsync ★★
() автор топика
Ответ на: комментарий от rsync

я вот одного не понимаю: почему нельзя поддерживать обратную совместимость?

Чтобы не тянуть костыли сквозь года, конечно.

Darth_Revan ★★★★★
()
Ответ на: комментарий от grem

На Free Pascal'е это будет как-то так:

program lzmonitorz;
	uses process, sysutils;
type
MonitorRecord = Record
        m_name: String[16];
        m_w, m_h, m_x, m_y, m_primary: Integer;
end;

var
	s1, s2: AnsiString;
	cptr1, cptr2, nlptr: Integer;
	monitor: MonitorRecord;
begin
	if RunCommand('/usr/bin/xrandr', [], s1) then
	while Pos(' connected', s1) <> 0 do begin
		cptr1 := Pos(' connected', s1);
		cptr2 := cptr1;
		while Copy(s1, cptr2, 1) <> Chr(10) do dec(cptr2);
		with monitor do begin
			m_name := Copy(s1, cptr2 + 1, cptr1 - cptr2 - 1);
			s2 := Copy(s1, cptr1, Length(s1) - cptr1 - 1);
			nlptr := Pos(Chr(10), s2);
			s2 := Copy(s2, 1, nlptr);
			inc(nlptr, cptr1);
			m_primary := Pos(' primary ', s2);
			if m_primary > 1 then m_primary := 1;
			cptr1 := Pos('x', s2);
			cptr2 := cptr1;
			while Copy(s2, cptr2, 1) <> Chr(32) do dec(cptr2);
			m_w := StrToInt(Copy(s2, cptr2 + 1, cptr1 - cptr2 - 1));
			s2 := Copy(s2, cptr1 + 1, Length(s2) - cptr1);
			cptr1 := Pos('+', s2);
			m_h := StrToInt(Copy(s2, 1, cptr1 - 1));
			s2 := Copy(s2, cptr1 + 1, Length(s2) - cptr1);
			cptr1 := Pos('+', s2);
			m_x := StrToInt(Copy(s2, 1, cptr1 - 1));
			cptr2 := Pos(' ', s2);
			m_y := StrToInt(Copy(s2, cptr1 + 1, cptr2 - cptr1 - 1));
			s1 := Copy(s1, nlptr, Length(s1) - nlptr);
		end;
		writeln(monitor.m_name);
		writeln('        name: ', monitor.m_name);
		writeln('           w: ', monitor.m_w);
		writeln('           h: ', monitor.m_h);
		writeln('           x: ', monitor.m_x);
		writeln('           y: ', monitor.m_y);
		writeln('     primary: ', monitor.m_primary);
	end;
end.

Живых Бейсиков, кстати, вагон и тележка, а не только gambas. bwbasic, X11-Basic, qb64,...

saahriktu ★★★★★
()
Ответ на: комментарий от saahriktu

Регэкспы в Паскале, если что, тоже есть. Вот справочный пример:

program Project1;
 
uses
  RegExpr;
 
var
  re: TRegExpr;
begin
  re := TRegExpr.Create('hello (.*?)!');
  if re.Exec('hello world! hello pascal!') then
  begin
    WriteLn(re.Match[1]);
    while re.ExecNext do
    begin
      WriteLn(re.Match[1]);
    end;
  end;
  re.Free;
end.

saahriktu ★★★★★
()
Ответ на: комментарий от Deleted

отличное решение для stable-веток

Разработчики Python сами обожглись на сём, потому, возможно, что Python 3 будет последним сломом API.

Darth_Revan ★★★★★
()

Вот, решение без уродования с процессами и без Qt/GDK (и без поддержки Wayland, да):

#!/usr/bin/env python
import sys
import yaml
import Xlib.display

if __name__ == "__main__":
    out = {}
    display = Xlib.display.Display()

    if not display.has_extension("RANDR"):
        raise OSError("XRandR is not available")

    window = display.screen().root
    screen_res = window.xrandr_get_screen_resources()
    timestamp = screen_res.config_timestamp
    primary_num = window.xrandr_get_output_primary().output

    for i in screen_res.outputs:
        monitor = display.xrandr_get_output_info(i, timestamp)
        if monitor.crtc == 0:
            continue
        crtc = display.xrandr_get_crtc_info(monitor.crtc, timestamp)
        out[monitor.name] = {
            "name"    : monitor.name,
            "w"       : crtc.width,
            "h"       : crtc.height,
            "x"       : crtc.x,
            "y"       : crtc.y,
            "primary" : 1 if i == primary_num else 0,
        }

    yaml.dump(out, sys.stdout, default_flow_style=False)
Вот так оно и должно быть сделано.

Darth_Revan ★★★★★
()
Последнее исправление: Darth_Revan (всего исправлений: 2)
Ответ на: комментарий от Darth_Revan

Разработчики Python сами обожглись на сём, потому, возможно, что Python 3 будет последним сломом API.

Судя по экспериментам с type hints в 3.8, надежды на это так себе.

Deleted
()
Ответ на: комментарий от aedeph_

Я уже использую. В дистрах многих он доступен в репах. В том же void'e добавили build template для сборки. Распространения как питон он не получит, но и нах надо.

Deleted
()
Ответ на: комментарий от saahriktu

Выглядит даже более ужасающе, чем perl, я впечатлён.

Darth_Revan ★★★★★
()
Ответ на: комментарий от Darth_Revan

во второй ветке тоже экспериментальные вещи были опциональны, и импортировались через тот же __future__. Но.

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.