The equivalent of Python getattr, but for index or key - python

If a complex container A contains some element xyz, which can be accessed by key or by index (similar to lists or dictionaries):
xyz = A[somekey]
xyz = A[someindex]
how would I access the element, given a string? Basically I'd like the equivalent of:
method_of_a = getattr(A, 'method_of_a') # gets A.method_of_a
prop_of_a = getattr(A, 'prop_of_a') # gets A.prop_of_a
but I don't know of anything like:
element_by_key = getitem(A, 'somekey')# get A['somekey']
element_by_index = getitem(A,'2')# get A[2]
The reason I want that, is that I should copy a property or an element.
The problem is that I can only access the base containers, and a string representation of where to look. A more realistic exaple would be:
# copy A.some.weird.path[0].including['Keys']
# to B.some.weird.path[0].including['Keys']
prop = magic_get_function(A, "some.weird.path[0].including['Keys']")
magic_set_function(B, "some.weird.path[0].including['Keys']", prop)
I'd very much like to not resort to eval, as eval is evil (or rather it's vulnerable).
If there's no other way than eval, how would you go at it?

Related

To use the parameter as a part of the name for a newly created variable

I wonder if there is a way to create variables automatically using strings, e.g. I have the following code (which does not work properly in Python):
def function(lst1, string1):
lst2 = 'processed_' + string1
lst2 = [] #here I created a string called lst2, but I want to use the string as the variable name.
for i in range(len(lst1)):
if abs(lst1[i]) >= 0.0001 :
lst2.append(i)
return lst2
function(list1, 'price') # list1 is a list which contains the index for column numbers, e.g., [1,2,3]
function(list1, 'promotion')
function(list1, 'calendar')
I would expect that with the function I would be able to create lists such as processed_price, processed_promotion, and processed_calendar, and the function will return these lists.
However the code above would not work as in Python. I wonder how should I write the code properly to achieve the same goal?
getattr(object, name, [default])
setattr(object, name, value)
To get or set values for a variable named via a string, use one of the above as appropriate. However, any time you use user input, it can be a source of injection attacks — the user could use a name that you did not expect them to use but the name is valid so the user gets access to data they should not have access to.
So it is usually advisable to use the user input as a key into a dictionary you define.
dictionary = {
'apple': 'my_value'
}
dictionary[user_input] = 'their_value'

Would a Python dictionary be the equivalent data structure to a Rexx compound variable?

I'm working on rewriting a lengthy Rexx script into a Python program and I am trying to figure out the best way to emulate the functionality of a Rexx compound variable. Would a dictionary be the best bet? Obviously, a dictionary will behave differently and won't be exactly the same as a compound variable.
Python dictionaries and Rexx stems are both associative arrays. They differ a bit in how they behave. Rexx's rules are very simple:
An array reference is split into the "stem" and the "tail", separated by a single dot.
The stem is a variable name, case-independently. This is the dictionary.
The tail is processed to identify an element of the array. It is split into one or more dot-separated substrings. Each substring is treated as a variable: if there is a variable with that case-independent name, its value is used instead of its name. Otherwise the name is uppercased and used. The string is put back together, dots and all. This is the key.
The array can have a default value, set by stem. = value, which applies to all unset elements.
So, the result of a an array reference stem.tailpart1.tailpart2.tailpart3 in Python is:
def evaluate_tail(tail, outer_locals):
result = []
for element in tail.split('.'):
if element in outer_locals:
result.append(str(outer_locals[element]))
else:
result.append(str(element).upper())
return '.'.join(result)
array_default_value = 4
stem = {'A.B.C': 1, 'A.9.C': 2, 'A..q': 3}
b = 9
d = 'q'
tail1 = 'a.b.c'
tail2 = 'a..b'
tail3 = 'a..d'
stem.get(evaluate_tail(tail1,locals()), array_default_value) # 'stem.a.b.c' >>> stem['A.9.C'] >>> 2
stem.get(evaluate_tail(tail2,locals()), array_default_value) # 'stem.a..b' >>> stem['A..9'] (not found) >>> (default value) >>> 4
stem.get(evaluate_tail(tail3,locals()), array_default_value) # 'stem.a..d' >>> stem['A..q'] >>> 3
Rexx-Stem variable and python-dictionaries are similar but there are differences.
Considder creating a RexxStem class based on a dictionary
Simple Stem expressions
a.b
can be translated to python as
a[b]
Compound Stem expressions
From my experience
a.b.c.d
would be translated to python as
a[b + '.' + c + '.' + d]
Try running the following rexx with your current interpretter and see what you
get:
a.2.3 = 'qwerty'
zz = 2'.'3
say a.zz
in some rexx interpreters you would get 'qwerty'. Not sure if that is all
Initializing a Stem Variables
in rexx you can initialize a stem variable lic
a. = 'abc'
Some common uses are
no = 0
yes = 1
found. = no
if ... then do
found.v = yes
end
....
if found.y = yes then do
..
end
or
counts. = 0
do while ...
if ... then do
counts.v = counts.v + 1;
end
end
Initial Value of a stem variable
Like all Rexx variables, the default/initial value of a variable so the default value of a.2.3 is A.2.3. If you are coming from another language this may seem strange but it can be quite handy in debugging - if a variable name pops up unexpectedly --> you have not initiated. It also means numeric expressions crash if you do not initialize a variable.
This not something you need to implement, just be aware of.
I am not a Python person but I know what a Dictionary is.
Depending on how complex the Rexx compound variable is, yes.
a.b
...is easily translatable to a dictionary.
a.b.c.d.e.f.g.h
...is less easily translatable to a dictionary. Perhaps a dictionary within a dictionary within a dictionary within a dictionary within a dictionary within a dictionary within a dictionary.

Entire dictionary being updated when using "append" or "extend", despite accessing a single element in the dictionary

I have a dictionary in the format:
dictionary= {reference:annotation}
where the reference refers to a position, and the annotation contains information about that location.
I want to find reference positions that overlap, and update the annotation when that occurs. The annotation that I want to update is accessed by dictionary["reference"].qualifiers["ID"] (the annotation contains a second dictionary, where I can access the information I want).
When if I try to add another ID to the annotation using: d
dictionary[reference].qualifiers["ID"].extend(["new ID"])
or
dictionary[reference].qualifiers["ID"].append("new ID")
all reference annotations in my dictionary are being updated with that new ID.
However, if do this using basic list comprehension I get the desired result:
dictionary[reference].qualifiers["ID"] = dictionary[reference].qualifiers["ID"] + ["new ID"]
Only the annotation at that reference is updated. Can anyone explain why I am getting a different result using "append" or "extend"?
The first example you give as not working works for me:
class Annotation:
def __init__(self, initial_val):
self.qualifiers = {'ID': [initial_val]}
an1 = Annotation("foo")
an2 = Annotation("bar")
d = {'ref1' : an1, 'ref2': an2}
print d['ref1'].qualifiers['ID']
print d['ref2'].qualifiers['ID']
d['ref1'].qualifiers['ID'].extend(['new foo'])
print d['ref1'].qualifiers['ID']
print d['ref2'].qualifiers['ID']
results in:
~ mgregory$ python foo.py
['foo']
['bar']
['foo', 'new foo']
['bar']
~ mgregory$
I think you have something wrong with the way you are creating annotations - possibly mistaking a shallow copy for a deep one, or a similar data structure pitfall like that.
You need to post actual code that doesn't work.
As a side note, the code you described as a comprehension, is not. It's just use of the array operator +.

Dynamically creating a class

I have a function which returns me two lists, symbols and data where the corresponding values are with the same index. For example symbols[i] gives the variable name and data[i] gives the actual value (int).
I would like to use these two lists to dynamically create a class with static values of the following format:
class a:
symbols[i] = data[i]
symbols[i+1] = data[i+1]
and so on so that I could later refer to the values like this:
a.symbols[i]
a.symbols[i+1]
where symbols[i] and symbols[i+1] should be replaced with the wanted variable name, like a.var1 or a.var2
How could this be achieved?
Edit: added detail below
So I have a main program lets say def main() which should read in a list.dat of this style:
dimension1;0.1
dimension2;0.03
dimension3;0.15
and separate the values to symbols and data lists.
So I don't know how many values there are exactly in these lists. I want to create a class dynamically to be able to refer to the values in the main program and to give the class to sub functions as an argument like def sub1(NewClass, argument1, argument2) etc. At the moment I am using a manually created simple python list (list.py) of the following format:
dimension1 = 0.1
dimension2 = 0.03
dimension3 = 0.15
and then using from list import * in the main program and also in the sub functions, which causes a SyntaxWarning telling me that import * only allowed at module level. So what I actually want is a smart and consistent way of handling the parameters list and transferring it to another functions
You can create a class dynamically with type. If I understand what you want to achieve here, your code will look like:
my_classes = []
for i in range(0, len(data), 2):
my_classes.append(
type('A%d' % i, (), {'var1': data[i], 'var2': data[i+1]})
)
I suspect what you actually want, re-reading the description, is to use type as follows:
NewClass = type('NewClass', (object,), dict(zip(symbols, data)))
Given a minimal example:
>>> symbols = 'foo bar baz'.split()
>>> data = range(3)
The outcome would be:
>>> NewClass.foo
0
>>> NewClass.bar
1
>>> NewClass.baz
2
Using zip allows you to easily create a dictionary from a list of keys and a list of associated values, which you can use as the __dict__ for your new class.
However, it's not clear why you want this to be a class, specifically.

It's possibile to use set function on a object basing only one attribute?

I'm creating this type of object:
class start_url_mod ():
link = ""
id = 0
data = ""
I'm creating a list of this object and I want to know if there is some way in order to delete one of then if I find same link attribute.
I know the function set() for the deleting of duplicates in a "sample" list, but there is something very fast and computational acceptable?
Use a dict key-ed on the attribute. You can preserve order with collections.OrderedDict:
from collections import OrderedDict
# Keep the last copy with a given link
kept_last = OrderedDict((x.link, x) for x in nonuniquelist).values()
# Keep the first copy with a given link (still preserving input order)
kept_first = list(reversed(OrderedDict((x.link, x) for x in reversed(nonuniquelist)).viewvalues()))
If order is not important, plain dict via dict comprehensions is significantly faster in Python 2.7 (because OrderedDict is implemented in Python, not C, and because dict comprehensions are optimized more than constructor calls; in Python 3.5 it's implemented in C):
# Keep the last copy with a given link but order not preserved in result
kept_last = {x.link: x for x in nonuniquelist}.values()
# Keep the first copy with a given link but order not preserved in result
kept_first = {x.link: x for x in reversed(nonuniquelist)}.values()
You can use a dictionary with the attribute that you're interested in being the key ...

Categories