Lookup dynamic dictionary key - python

I'm trying to lookup a static value combined with a dynamic variable in a dictionary.
For example, a key in my_dict is: static_value1
My current code is:
dynamic_variable = 1
string = "static_value" + str(dynamic_variable)
my_dict[string]
But, with this code string is actually: 'static_value1'
I need it without the quotes to properly look up the dictionary key.
How could I do this? Hope it makes sense.

You can get the value of a "dynamic variable" by using the globals function:
my_dict[globals()[string]]
assuming that the variable is in global (module) scope. (If it isn't, use locals() instead).
This is faster and safer than using eval.
In general, you should try to avoid looking variables up dynamically in Python (the exception is when working with functions like __getattr__). Instead, consider using a dictionary to store mappings of names to keys. Dictionaries are more convenient than a collection of similarly-named variables in several ways.

It sounds like you are trying to change the string into a variable name before using it as a key. Perhaps this?
my_dict[eval(string)]
As nneonneo mentioned in his answer, using eval with a user supplied string is generally a bad idea, because it represents a security vulnerability, since you have just given your user the ability to execute arbitrary code on your system.

Related

Access dictionary several times or store in temporary variable

Say, I need to use some value from Python dictionary several times in one piece of code. What are the best practices?
Access dictionary once, store value in some temporary variable and use this variable:
value = d['my_key']
do_some_work(value)
do_some_other_work(value)
and_again(value)
or access dictionary everytime a need this value:
do_some_work(d['my_key'])
do_some_other_work(d['my_key'])
and_again(d['my_key'])
The first approach leads to more readable functions when called, in particular when the key of the dictionary is long or not self explanatory. However, the reader will always have to check the origin of the variable if he's not willing to blindly trust the name of the variable. So why not calling the dictionary directly then?
Personally, I use both approaches according to the use case. If the key or dictionary names are long or not sufficiently self-explanatory, I create a temporary variable. Otherwise, I access the dictionary directly when calling the functions.
For a dict, the average time complexity of accessing an item is constant O(1), see
Python Time Complexity.
So, I wouldn't expect much difference in performance.

How to use %s to name a list

I'm trying to create a system on Python that allows me to create a list called (user)total, 'user' being the name of the user before total. However this is subjective as any account with any username could be made within my program.
I have tried to use
%stotal = [''] %user
however this comes up with a syntax error. How would I manage to do this?
You can't do that kind of meta-programming in python! (not with the syntax you posted)
But instead you can create a dictionary of lists indexed by the user name:
total = {}
total['username1'] = [''] #list for this username total
total['username2'] = ['']
etc.
It is possible. Hopefully seeing how will help to illustrate why, as Hyperboreus says, it's not a good idea.
If you do dir() in your interactive Python environment, you'll get a list of names that are available in your current scope. There will always be one called __builtins__, which exposes all of the functions and constants in the builtins module. These functions and constants are defined to be exactly the same ones that are available right from the start of your Python session in the global namespace, which you can take a look at with the builtin function globals().
In accordance with the Python data model, every Python object has an element named __dict__ that's a dictionary object whose keys are member names. If obj is the name of some Python object in the current scope, obj.__dict__["keyname"] will access the same member that you could get to more simply through obj.keyname.
So putting this together, you can set key/value pairs in __builtins__.__dict__ directly:
>>> __builtins__.__dict__["testvarname"] = "testval"
>>> print testvarname
testval
Whew! Getting pretty abstract pretty quick here. This might be useful for defining behavior based on user input or something else that you might not know until runtime... but you can probably see how you're working through a lot of complexity to get there and sort of circumventing the normal rules that Python sets out to try to help you keep your programs organized and easy to understand. xndrme's answer is likely to be the more straightforward way to solve the bigger problem you're facing.

Is Python static typed?

I know Python is dynamic typed, duck typed and is also strong. In some cases, we have to make sure it is declare as a list or a dictionary beforehand in order to use them... so can I say Python is also statically typed language?
No, Python is not statically typed.
In static typing names are bound to both a type and an object (or value), in Python names are only bound to objects. At any time you can reassign a name to an object of a different type, which you cannot do in statically typed languages.
I'm not sure what you mean by needing declaring your variables beforehand, but my guess is that you are actually just creating an empty list or dictionary and assigning it to a name.
Consider this line of code:
x = [] # (or {})
You are not "declaring a variable as a list (or dict)" before using it. You are creating a list ([]) (or dict {}) and then assigning it as the value of a variable (x). This does not mean that x now has a type. You could later assign a string to x:
x = 'a string'
and Python would have no problem with this.
I wonder if you are being confused by a feature of another language, such as Perl's autovivification feature, which let's you treat an uninitialized scalar variable as though it were a reference to a list or hash. Are you thinking that Python is less "dynamic" because it lacks such a feature? If you are actually looking for such a thing, look into the defaultdict class from the collections module.

iterate a list when list name is dynamically generated

How do I iterate through a list whose name will be dynamically generated?
boneList_head =['def_neck', 'def_armbase']#hard coded list
itemType='head'# result of a user button press
...
def selectBones():
global itemType
bones =('boneList_'+itemType)# evaluates as a string , not name of a list
for bone in bones:
cmds.select(bone, tgl=True)
the problem is bones is getting evaluated as a string, when I need it to evalute as the name of a list.
Dynamically generating variable names is almost always a bad approach. Use a dictionary!
bonedict = {'boneList_head': ['def_neck', 'def_armbase']}
itemType='head'
def selectBones(itemType):
bones = bonedict['boneList_' + itemType]
for bone in bones:
cmds.select(bone, tgl=True)
Please ignore my previous answer (visible in my edit history) which was stupid -- boneheaded, even. But I blame its stupidity on dynamic variable name generation!
Let me elaborate on why dynamic variable name generation is a bad idea.
Because dynamic variable generation masks variable name definitions. It's hard to tell what has been defined and what hasn't, so it's easy to accidentally redefine a variable. This is a major source of potential bugs.
Because dynamic variable manipulation hides state changes under another layer of obfuscation. To some degree, this is true anytime you create a dictionary or a list. But one expects lists and dictionaries to demand a little extra thinking. Variable names, on the other hand, should be dead simple. When variable definitions and redefinitions require deep thought to understand, something is wrong.
Because dynamic variable generation pollutes the namespace. If you have so many variables that you have to automatically generate them, then they should live in their own namespace, not in the locals of a function, and definitely not in the global namespace. In his style guide for the linux kernel, Linus Torvalds advises that if a function has more than 5-10 local variables, you're doing something wrong.
Because dynamic variable generation contributes to high coupling, which is a bad thing. If you assign to values to a dictionary, you can pass that dictionary back and forth until the cows come home, and all anyone has to know about is that dictionary. If you dynamically create variable names in the global namespace of a module, then if another module wants to access those variable names, it has to know all about the way they were generated, what other variables in that module are defined, and so on. Also, passing the variables around becomes much more complex -- you have to pass around a reference to the module itself, probably using sys.modules or other questionable constructs.
Because dynamic variable generation is ugly. eval looks neat and clean, but it really isn't. It can do anything. Functions that can do anything are bad, because you can't tell at first glance what they're doing here. A well-defined function does one thing, and does it well; that way, whenever you see that function, you know exactly what's happening. When you see eval, literally anything could be happening. In this sense, eval is like goto. The problem with goto is not that you can't use it correctly; it's that for every possible correct use of goto, there are 500,000,000 terrifyingly wrong ways to use it. I won't even discuss the security problems here, because in the end, that's not the real problem with eval.
I agree with the other comments that your approach is probably not the best. But the following should work:
bones = eval('boneList_' + itemType)
This will run the python interpreter on "boneList_head", and return the list.
NOTE: As Adam Mihalcin mentioned in the comments, you should be very careful about only running eval on data that you trust or have validated. A malicious user could inject arbitrary code into the itemType variable to access the os, etc.
This is an ugly hack, but it works...(of course, you need to get the correct module)
import sys
boneList_head =['def_neck', 'def_armbase']
itemType='head'
...
def selectBones():
global itemType
bones=vars(sys.modules["__main__"])['boneList_'+itemType]
for bone in bones:
cmds.select(bone, tgl=True)
This really isn't different than what other people are saying however-- We're using vars to construct a dictionary to get the list you want -- why not just pass a dictionary (or the correct list) to the function selectBones in the first place?

GetAttr Function Problems (Python 3)

I have the following in a Python script:
setattr(stringRESULTS, "b", b)
Which gives me the following error:
AttributeError: 'str' object has no attribute 'b'
Can any-one telling me what the problem is here?
Don't do this. To quote the inestimable Greg Hewgill,
"If you ever find yourself using quoted names to refer to variables,
there's usually a better way to do whatever you're trying to do."
[Here you're one level up and using a string variable for the name, but it's the same underlying issue.] Or as S. Lott followed up with in the same thread:
"90% of the time, you should be using a dictionary. The other 10% of
the time, you need to stop what you're doing entirely."
If you're using the contents of stringRESULTS as a pointer to some object fred which you want to setattr, then these objects you want to target must already exist somewhere, and a dictionary is the natural data structure to store them. In fact, depending on your use case, you might be able to use dictionary key/value pairs instead of attributes in the first place.
IOW, my version of what (I'm guessing) you're trying to do would probably look like
d[stringRESULTS].b = b
or
d[stringRESULTS]["b"] = b
depending on whether I wanted/needed to work with an object instance or a dictionary would suffice.
(P.S. relatively few people subscribe to the python-3.x tag. You'll usually get more attention by adding the bare 'python' tag as well.)
Since str is a low-level primitive type, you can't really set any arbitrary attribute on it. You probably need either a dict or a subclass of str:
class StringResult(str):
pass
which should behave as you expect:
my_string_result = StringResult("spam_and_eggs")
my_string_result.b = b
EDIT:
If you're trying to do what DSM suggests, ie. modify a property on a variable that has the same name as the value of the stringRESULTS variable then this should do the trick:
locals()[stringRESULTS].b = b
Please note that this is an extremely dangerous operation and can wreak all kinds of havoc on your app if you aren't careful.

Categories

Resources