LINUX.ORG.RU

Какой быдлокод лучше для замены шаблона в словаре?

 


1

2

С точки зрения разработки, как лучше заменить шаблон:

  1. пройти рекурсивной функцией по словарю и заменить значение

  2. Завернуть в JSON, заменить, развернуть обратно в словарь?

  1. Что если тебе нужно будет заменить NaN на VaSyaN?
  2. Что если тебе нужно будет заменить символ, которые заэскейпится при сериализации в джысон?
  3. Что если искомая последовательность встретится не только в значениях, ноти в ключах?

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

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

вариант 2 не нормально работать не будет.

anonymous
()
Ответ на: комментарий от MOPKOBKA

Оно загружается из конфига. Всё равно идти по рекурсии.

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

Ну конфиг, в некотором роде, тоже можно расценивать как входные данные, а там ни в чём нельзя быть уверенным на 100%. К слову, " – это тоже видимый ASCII символ.

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

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

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

Ну вот вроде ОК:

    def replace_arg(self, inplace, arg, args: Union[Dict, List, str]):
        """Replace template in arguments."""
        if isinstance(args, list):
            for index, value in enumerate(args):
                if self.replace_arg(
                    inplace=inplace, arg=arg, args=value) is not None:
                    args[index] = arg

        elif isinstance(args, dict):
            for key, value in args.items():
                if self.replace_arg(
                    inplace=inplace, arg=arg, args=value) is not None:
                    args[key] = arg

        if args == inplace:
            return arg
steemandlinux ★★★★★
() автор топика
Последнее исправление: steemandlinux (всего исправлений: 2)

1. с приправой итеративной функциональщЕнной (мутабельной ага побочки наше всё)

зы. всяко в стдлиб есть итератор дерева (по типу для файлводерева есть специализация os.walk)

ззы


   set(TopLevelReplacer(Nodedict)for Nodedict in somestd.Traveler(MortyRecDict))
qulinxao3 ★★
()
Последнее исправление: qulinxao3 (всего исправлений: 1)
Ответ на: комментарий от steemandlinux

Возможность непреднамеренной замены в ключах и литералах true, false остаётся

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

зачем колхозить если есть на https://github.com/python/cpython/tree/main/Lib or pypi

например:

https://pypi.org/project/python-benedict/

либо взять за основу os.walk и выточить свой

имхо тут реально итератор обхода дерева подобный os.walk но для специализированной СД рулит

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

а где сама замена значения походящего ключа(ей) и на что ? сейчас у тя всё для случая inplace==arg ( а это бывает только но не всегда при верхем вызове) чёт у тя рекурсия хромая

та замена только на первом уровне срабатывает в остальных случаях args достоверно не inplace - если это дерево - для графа конечно можеть и ...

короче как то сложно в вашей реализации - более того зачем копипастить можно же одним циклом что словарь что список обходить:

def replace_arg(self, inplace, arg, args: Union[Dict, List, str]):
    if not isinstance(args, (list, dict, str)):
        raise SystemExit("ой всё")

    if not isinstance(args, (list, dict)):
        pass  # str ?!?
        return  # ???

    if args != inplace:
        return

    def pairs(v):
        return enumerate(v) if isinstance(v, list) else v.items()

    for key, value in pairs(args):
        if self.replace_arg(inplace, arg, args=value):
            args[key] = arg
    return arg

и в целом inplace и arg постоянны поэтому их по стеку можно и не гонять - а типо создать обьект с этими полями и уже этого анонима сделать сall по замене

ваще радостно как то

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

дык в том и прикол -

поверхностно(?!) смотря на твой код очевидно что он хромает на большое количество конечностей сороконожки

ибо по факту эквивалентные преобразования делают очевидным что тот код который(на который я трансформацию привёл - по началу для удаления копипасты(один и тотже по сути перебор содержимого контейнера )) выше, и вращением веток стало очевидно, что либо эскиз кода либо он заведомо не универсален

т.е если код такого качество

то второй вариант - с заменой регуляркой в джсон-строке - получает преимущество но всё равно не побеждает

так то 1 вариант (рекурсивная замена по условию) предпочтительней

но вот код изначальный Ваш - он какой то радостный и божественный

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

упс понял внесёную мною из за побочки багу

но тогда inplace семантика оказалась иной

всяко тогда изначальное задание не полное - ибо если нужно заменить не у контейнера для всех ключей значения на arg

а у некоторого конкретного ключа/индекса

т.е вам очевидно лучше знать что вам надо

из ТС не вполне очевидно насколько частично вам достаточно

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

Смотрел сообщения твоей первой инкарнации и сильно удивился, что они на русском. Более того, идеи все связанные, излагались в виде полных предложений, был даже сарказм. Что случилось дальше? Как так случилось, что ты перешёл с русского на китайско-русский переводчик?

anonymous
()
Ответ на: комментарий от qulinxao3

args - список аргументов с шаблоном «<value_arg>», загружаемые из конфига.

arg - аргумент, на который надо поменять шаблон «<value_arg>». Т.к. протокол сеть или серийник, он может быть только строкой.

inplace это сам шаблон «<value_arg>»

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

китайско-русский

да этож русский сибиряк, просто по всей видимости вещества случились или ещё какой диагноз

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

время вперёд

зы. «не все доживают до стадвадцати»

ззы: [a]ru.wikipedia.org/wiki/Минималистская_программа#cite_ref-2[/a]

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

преамбула: понятней было бы на каких входах какие выходы

т.е скорее?:

def change_in_value_target2new(self, target, new, places: Union[Dict, List, str]):
    if not isinstance(places, (list, dict, str)):
        raise SystemExit("ой всё")

    if not isinstance(places, (list, dict)): 
        return  places==target

    def pairs(v):
        return enumerate(v) if isinstance(v, list) else v.items()

    for key, value in pairs(args):
        if self.change_in_value_target2new(target, new_value, places=value):
            args[key] = arg
    
    return places==target #?!?

qulinxao3 ★★
()

пройти рекурсивной функцией по словарю и заменить значение

Это. Должен же в питоне быть простейший tree walk?

И да, где примеры — словарик, шаблоны? Что надо сделать-то?

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

лютый быдлокод, тебе после этого ни одна эйчарка не даст

Эйчаркам на твой кот турбофиолетово, они в нём (обычно) всё равно ничего не понимают.

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

я думаю лучше создать новый словарь:

def dickt_replace(d, s, r):
    if isinstance(d, dict):
        return {k: r if k == s else dickt_replace(v, s, r) for k, v in d.items()}
    elif isinstance(d, list):
        return [dickt_replace(item, s, r) for item in d]
    else:
        return d
In [4]: dickt_replace({'spam': [{'foo': 'bar'}]}, 'foo', 'baz')
Out[4]: {'spam': [{'foo': 'baz'}]}
rtxtxtrx
()
Последнее исправление: rtxtxtrx (всего исправлений: 1)

Прогони тысячи раз, выяснишь что быстрее, то и используй. Если читаемость важнее - то что считаешь читаемее

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

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

rtxtxtrx
()

Можно слегка обобщить это всё*:

def identity (x):
    return x

def partial (f, *args):
    return lambda *more: f(*args, *more)

def walk (inner, outer, tree):
    if isinstance(tree, dict):
        return dict(map(lambda entry: [inner(entry[0]), inner(entry[1])], tree.items()))
    elif isinstance(tree, list):
        return outer(list(map(inner, tree)))
    else:
        return outer(tree)

def prewalk (f, tree):
    return walk(partial(prewalk, f), identity, f(tree))

def postwalk (f, tree):
    return walk(partial(postwalk, f), f, tree)
def foo_bar_to_baz (value):
    if isinstance(value, dict) and "foo" in value and value["foo"] == "bar":
        value["foo"] = "baz"
    return value

d = {'spam': [{'foo': 'bar'}]}

print(d)
print(prewalk(foo_bar_to_baz, d))
d = {'spam': [{'foo': 'bar'}]}
d = {'spam': [{'foo': 'baz'}]}

Можно обернуть walk/prewalk/postwalk в функцию, которая будет принимать ключ и новое значение, или вообще словарь замен — дело хозяйское. Главное, сам обход дерева теперь каждый раз заново песать не надо будет.


*содрано с https://github.com/clojure/clojure/blob/master/src/clj/clojure/walk.clj

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

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

rtxtxtrx
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.