How can you dynamically create variables?
Unless there is an overwhelming need to create a mess of variable names, I would just use a dictionary, where you can dynamically create the key names and associate a value to each.
a = {}
k = 0
while k < 10:
# dynamically create key
key = ...
# calculate value
value = ...
a[key] = value
k += 1
There are also some interesting data structures in the collections
module that might be applicable.
Create variables with specific type on the fly in Python
Well, without getting into the details of your nesting, you could attach a variable type to the name by using a tuple.
I've done this on 2 of your variable names : ('_idx_brg',str), ('stn','int')
Rather than using zip
, you'll need to hook that back up to your nested tuples and you'll also need to add error handling in case the string value from the file doesn't fit the expected variable type.
import builtins
import pdb
def set_attr(tgt, names, values):
try:
for name, value in zip(names, values):
cls_ = None
if isinstance(name, str):
setattr(tgt, name, float(value))
elif isinstance(name, tuple):
name, cls_ = name
if callable(cls_):
setattr(tgt, name, cls_(value))
elif isinstance(cls_, str):
cls_ = globals().get(cls_) or getattr(builtins, cls_)
setattr(tgt, name, cls_(value))
else:
raise ValueError("variable types have to be a string or callable like `int`,`float`, etc")
except (ValueError,TypeError,AttributeError) as e:
print(f" somethings wrong:\n{dict(exception=e, name=name, cls_=cls_, value=value)}")
#raise
#pragma: no cover pylint: disable=unused-variable
except (Exception,) as e:
if 1:
pdb.set_trace()
raise
class Foo:
pass
variable_names = ('_idx_brg', 'stn', 'stn_rel', '_n_lines', '_brg_type')
values = (1.0, 1, 1.2, 1.3, 1.4, 1.5)
foo = Foo()
print("\n\nsetting for foo")
set_attr(foo, variable_names, values)
print("\n\nfoo:", vars(foo))
variable_names2 = (('_idx_brg',str), ('stn','int'), 'stn_rel', '_n_lines', ('_brg_type','xxx'))
bar = Foo()
print("\n\nsetting for bar:")
set_attr(bar, variable_names2, values)
print("\n\nbar:", vars(bar))
output:
setting for foo
foo: {'_idx_brg': 1.0, 'stn': 1.0, 'stn_rel': 1.2, '_n_lines': 1.3, '_brg_type': 1.4}
setting for bar:
somethings wrong:
{'exception': AttributeError("module 'builtins' has no attribute 'xxx'"), 'name': '_brg_type', 'cls_': 'xxx', 'value': 1.4}
bar: {'_idx_brg': '1.0', 'stn': 1, 'stn_rel': 1.2, '_n_lines': 1.3}
br>
You could even build your own classes.
class Myclass:
def __init__(self, value):
self.value = value
#part of your name/type tuples...
(('somevar', Myclass), ('_idx_brg',str)...)
edit re. yaml:
I am not testing this so you may have to adjust a bit, esp around the exact yaml to get a dict with a nested varnames
dict in it.
---
varnames:
_idx_brg: str
stn : int
from yaml import safe_load as yload
with open("myconfig.yaml") as fi:
config = yload(li)
mapping = {}
#the yaml is all strings right now
# map it to actual types/classes
for name, type_ in config["varnames"].items():
cls_ = globals().get(type_) or getattr(builtins, type_)
mapping[name] = cls_
#using it
for name, value in zip(names, values):
#fall back to `float` if there is no special-case for this varname
cls_ = mapping.get(name, float)
setattr(tgt, name, cls_(value))
Now, this does rely on all instances of a given variable name having the same type no matter where in the data hierarchy, but that's just best practices.
The other thing is that, if I have one area that looks a bit fishy/brittle to me, it is your complex nesting with tuples of values and names that somehow need to be always in synch. Much more so than your basic requirement to load text data (whose format is not under your control) but then format it different ways. I'd work at getting your names to flow more naturally with the data, somehow. Maybe try to identify incoming data by record types and then assign a mapping class to it? Same thing as what you're doing, really, just not relying on complex nesting.
Or maybe, going from your remark about row, column, you could put all that into the yaml config file as well, load that into a mapping data structure and explicitly use indices rather than nested loops? Might make your code a lot simpler to reason about and adjust for data changes.
There are also interesting things in the Python data parsing space like Pydantic. Might or might not be helpful.
Run a loop to generate variable names in Python
Use the inbuilt glob
package
from glob import glob
fullpath = f'C:\Users\siddhn\Desktop\phone[1-6].csv'
dfs = [pd.read_csv(file) for file in glob(fullpath)]
print(dfs[0])
Dynamically create variable names?
you can use dictionary like this: examples
>>> a = ['hello', 'banana', 'apple']
>>> my_dict = {}
>>> for x in range(len(a)):
... my_dict[x] = a[x]
...
>>> my_dict
{0: 'hello', 1: 'banana', 2: 'apple'}
>>> my_dict[1]
'banana'
Python. How to dynamically create variables based on number of lines in a file?
It is almost always a bad idea to create variable names based on some programmatic value. Instead use a native data structure. In this case it sounds like a list
is what you need.
Here is a way to loop through a file and collect pairs of lines into a list of lists.
var = []
last_line = None
for line in open('data.txt', 'rU'):
if last_line:
var.append([last_line, line.strip()])
last_line = None
else:
last_line = line.strip()
if last_line:
var.append([last_line])
print(var)
Results:
[['line1', 'line2'], ['line3', 'line4'], ['line5', 'line6']]
how to assign a python variable whose name is generated on-the-fly?
you could do
globals()['yourvariables'] = variable
This adds the variable to the global namespace. I am not going to comment on whether it is a good idea or a bad one.
how to make variable name dynamic
The proper way to do it would be to use a dictionary rather than declaring variables :
s = open("Lines_only.txt", "r")
j = 1
v_dict = {}
for i in s:
line = i.strip()
v_dict[f"v{j}"] = float(line)
print(v_dict[f"v{j}"] )
j +=1
s.close()
#Then here access to the variables using v_dict["v1"], v_dict["v2"], ...
However, if what you want is really to declare a variable this is possible too (but you should still use the first option if possible)
s = open("Lines_only.txt", "r")
j = 1
v_dict = {}
for i in s:
line = i.strip()
globals()[f"v{j}"] = float(line)
print(globals()[f"v{j}"])
j +=1
s.close()
#Then here access to the variables using v1,v2, ...
sum_result = v1+v2
Related Topics
Accessing Dict Keys Like an Attribute
How to Base-64 Encode a Png Image for Use in a Data-Uri in a CSS File
Give the Python Terminal a Persistent History
Converting Python Objects for Rpy2
Creating Pyqt5 Buttons in a Loop: All Buttons Trigger the Same Callback
Subprocess.Popen: 'Oserror: [Errno 13] Permission Denied' Only on Linux
Trouble Importing Tabulate in Python 3.4
Cross Platform Numpy.Random.Seed()
Convert Utc Datetime String to Local Datetime
CSS Not Loading Wrong Mime Type Django
Move and Zoom a Tkinter Canvas with Mouse
Why Xgrabkey Generates Extra Focus-Out and Focus-In Events
A Way to "Listen" for Changes to a File System from Python on Linux
Multiprocessing Module Showing Memory for Each Child Process Same as Main Process