LINUX.ORG.RU

создать и записать переменную по имени

 ,


0

1

Вот есть всякие types.SimpleNamespace() и прочие NamedTuple. И у них из строки может появиться переменная, доступная через точку, например test.newvar = 3

А как самостоятельно добавить переменную, имя которой задано строкой? Поясню что хочу:

import types
p = types.SimpleNamespace()
p.test = 123 # верно
p.add_var("varname", 0) # не знаю как это сделать
def meow(p):
    p.test += 1
    p.varname += 1
meow(p)
т.е. внутри функции, я ожидаю, что и test и varname существуют.

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

Вот есть всякие types.SimpleNamespace()

Не являюсь питонячим экспертом,

Возможно, какие-то из этих способов тебе неизвестны, и на самом деле нужны они:

from types import SimpleNamespace as SN

#Задание нужных полей в конструкторе
sn1 = SN(x = 1, y = 2)
print(sn1.x, sn1.y)

#Через распаковку словаря
dict2 = {'x': 1, 'y': 2}
sn2 = SN(**dict2)
print(sn2.x, sn2.y)

#Через распоковку словаря in-place
sn3 = SN(**{'x': 1, 'y': 2})
print(sn3.x, sn3.y)
Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

Нет. Вот функция, которая мне была нужна. Если есть произвольная SimpleNamespace структура, выведенная в строку при помощи str(SN), то обратно запихать ее в SimpleNamespace можно при помощи самописной функции:

import ast
import types

def nsp_string(_s):
	p = types.SimpleNamespace()
	if(not _s.startswith("namespace(")):
		return p
	sl = _s[10:].split("=")
	for i in range(1, len(sl)):
		nn = ""
		ps = " " + sl[i - 1]
		for j in range(1, len(ps)):
			nn = ps[len(ps) - j:]
			if(nn[0] == " "):
				nn = nn[1:]
				break

		s = sl[i]
		last = 0
		for j in range(len(s)):
			if(s[j] == ","):
				last = j
		if(i == (len(sl) - 1)):
			s = s[:(len(s) - 1)]
		else: s = s[:last]
		setattr(p, nn, ast.literal_eval(s))
	return p

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

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Если есть произвольная SimpleNamespace структура, выведенная в строку при помощи str(SN), то обратно запихать ее в SimpleNamespace можно при помощи самописной функции

Нет под рукой интерпретатора python, но это точно не делается чем-то типа x = eval(repr(x))[\inline]?

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

но это точно не делается чем-то типа

Нет, и даже ast.literal_eval работает лишь с вложенными массивами, а остальное что делает моя функция - расплетает simpleNamespace.

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Меня всё равно не покидает ощущение, что ты пишешь какой-то велосипед, извини.

Если не катит связка eval/repr, то уж pickle должен сплетать-расплетать что угодно.

Как буду у компьютера, посмотрю подробнее твой код.

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

Так это и есть велосипед, так еще и медленный (не оптимальный), но мне его хватает. Про pickle не в курсе был. Если потребуется, надо будет и его посмотреть, но пока и своего лисапета хватает.

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Про pickle не в курсе был. Если потребуется, надо будет и его посмотреть, но пока и своего лисапета хватает

А его и смотреть нечего, тебе надо две функции: pickle.dump(obj, file) и obj = pickle.load(file) Проще пареной репы. А свой велосипед выкидывай.

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

Ещё есть cPickle, интерфейс идентичный, но он быстрее, так как написан полностью на сях. Обычно используют cPickle, а если по каким-то причинам нет возможности его загрузить - тогда уже стандартный pickle.

Crocodoom ★★★★★
()
Ответ на: комментарий от eternal_sorrow
>>> import pickle
>>> a = [(1, 2, 3), (4, 5, 6)]
>>> s = pickle.dumps(a)
>>> b = pickle.loads(s)
>>> b
[(1, 2, 3), (4, 5, 6)]
>>>
I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от Crocodoom

Вроде хорошо всё, но нужно читаемое строковое представление, как это делает str. Этот pickle не поддерживает строковую форму вывода?

>>> import pickle
>>> a = {}
>>> a["test"] = [(123, 456), (768, 444, 555), "hehe"]
>>> a["lol"] = ("???", [(1, 2, 3), "rrr", [3, 4]])
>>> s = pickle.dumps(a)
>>> s
b'\x80\x03}q\x00(X\x04\x00\x00\x00testq\x01]q\x02(K{M\xc8\x01\x86q\x03M\x00\x03M\xbc\x01M+\x02\x87q\x04X\x04\x00\x00\x00heheq\x05eX\x03\x00\x00\x00lolq\x06X\x03\x00\x00\x00???q\x07]q\x08(K\x01K\x02K\x03\x87q\tX\x03\x00\x00\x00rrrq\n]q\x0b(K\x03K\x04ee\x86q\x0cu.'
>>> b = pickle.loads(s)
>>> b
{'test': [(123, 456), (768, 444, 555), 'hehe'], 'lol': ('???', [(1, 2, 3), 'rrr', [3, 4]])}
>>>

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от Crocodoom

С типом SimpleNamespace он тоже корректно работает. Но жаль что не читаемая строка...

>>> import pickle
>>> import types
>>> p = types.SimpleNamespace()
>>> p.test = "haha"
>>> p.qqq = 123
>>> p.arr = [(123, 3, 4, 5), "?"]
>>> s = pickle.dumps(p)
>>> s
b'\x80\x03ctypes\nSimpleNamespace\nq\x00)Rq\x01}q\x02(X\x04\x00\x00\x00testq\x03X\x04\x00\x00\x00hahaq\x04X\x03\x00\x00\x00arrq\x05]q\x06((K{K\x03K\x04K\x05tq\x07X\x01\x00\x00\x00?q\x08eX\x03\x00\x00\x00qqqq\tK{ub.'
>>> b = pickle.loads(s)
>>> b
namespace(arr=[(123, 3, 4, 5), '?'], qqq=123, test='haha')
>>> p
namespace(arr=[(123, 3, 4, 5), '?'], qqq=123, test='haha')
>>>

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Вроде хорошо всё, но нужно читаемое строковое представление, как это делает str.

Ну repr() вполне неплохо читается, и в большинстве случаев берётся eval-ом

Например, примеры из твоих последних сообщений проходят «eval-repr» тест.

>>> a = {}
>>> a["test"] = [(123, 456), (768, 444, 555), "hehe"]
>>> a["lol"] = ("???", [(1, 2, 3), "rrr", [3, 4]])
>>> a == eval(repr(a))
True
>>> repr(a)
"{'lol': ('???', [(1, 2, 3), 'rrr', [3, 4]]), 'test': [(123, 456), (768, 444, 555), 'hehe']}"
>>> from types import SimpleNamespace as namespace
>>> p = namespace()
>>> p.test = "haha"
>>> p.qqq = 123
>>> p.arr = [(123, 3, 4, 5), "?"]
>>> p == eval(repr(p))
True
>>> repr(p)
"namespace(arr=[(123, 3, 4, 5), '?'], qqq=123, test='haha')"

Во втором случае пришлось присвоить SimpleNamespace псевдоним namespace, но это мелочи.

Приведи пример данных, на которых у тебя p != eval(repr(p)). В общем случае такой пример легко привести, но у тебя-то отладочные данные, там всё примитивно должно быть.

Тем не менее, кроме pickle и eval-repr ещё есть модуль json.

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

Во втором случае пришлось присвоить SimpleNamespace псевдоним namespace, но это мелочи.

Без этого способ не работает? Может это была причина?

UPD: проверил, так и есть, без «from types import SimpleNamespace as namespace» оно не может парсить eval-ом, жалуется что типа namespace нету. А с этой строкой - всё заработало!

Спасибо, что ж, это полезно, лучше чем мой велосипед.

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

Без этого конечно не работает. Потому что eval просто выполняет произвольный питоновский код, и не может знать, что такое namespace, если это имя не было объявлено ранее.

>>> import types
>>> p.test = "haha"
>>> p.qqq = 123
>>> p.arr = [(123, 3, 4, 5), "?"]
>>> repr(p)
"namespace(arr=[(123, 3, 4, 5), '?'], qqq=123, test='haha')"
>>> eval(repr(p))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'namespace' is not defined

Но ему легко это объяснить:

  1. Так:
    >>> from types import SimpleNamespace as namespace
    >>> p == eval(repr(p))
    True
    
  2. Или так:
    >>> namespace = types.SimpleNamespace
    >>> p == eval(repr(p))
    True
    
  3. Или так:
    >>> p == eval(repr(p), {'namespace': types.SimpleNamespace})
    True
    

Последний способ наверное самый правильный, но можешь выбрать любой.

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

Спасибо, вот третий способ шикарен, требуется тупо import types, а дальше все сосредоточено в той же строчке, где и преобразование. Это удобно и логично.

Как можно не любить язык Python? Я как-то даже и не осознавал таких возможностей языка, когда критиковал его :)

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