iterate a list when list name is dynamically generated - python

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?

Related

Saving and reassigning global variables dict in Python

I'm working in a large Python codebase which has its own functions defined for running certain sections of code called "rules". We have these rules defined in a certain place, and to run them we call the following function with their name as an argument:
runRule(<name of rule>)
Under the hood I don't know how it works, and don't have access to that information (sadly), but I think it does something like copying and pasting the rule code in the current position. I know it's not ideal and messy, but I don't have a choice but to work with it as it is.
My concern is that using runRule could potentially modify the local/global variables in the current namespace in an undesirable/unexpected way.
My question is whether something like the following code would make sense to avoid my concern?
# (using deepcopy didn't work when I tried... so will have to settle for a shallow copy)
globals_temp = dict(globals())
runRule("my_edit_rule")
# restore globals to what it was before running the rule
globals().update(globals_temp)
# this was added to globals originally and is no longer needed
del globals()["globals_temp"]
I know it's yuck code, but it may be my only option given then codebase I'm working with...

Alternatives to storing variables globally

I am starting out with Python now, working on the Learn Python The Hard Way, on exercise 36. I want to create a good game, and learn some more techniques before moving on with the next exercise. I haven't approached the subject of Classes and Object yet, yet I want to see if I can do something that would be a bit more complex than a standard first 'choose-your-own-adventure' game.
I want to collect four different keys in 'Ganon's Lair', and then use those four keys to open a door in the 'main-hall'. I already have quite some of it worked out (not elegantly), but I still need to figure out how to store keys without them getting erased. An unelegant way is to assign them as global variables, such as I do here.
def grass_room():
global key1
grass_instructions = """As you enter the lair of the grass room, you see
a spider hanging on the ceiling, with his
big eye focused on you. You could grab your 1.slingshot,
or perhaps 2.make a run for the green-coloured key under his
tail?"""
print grass_instructions
gohma_boss = raw_input("> ")
if gohma_boss == "1":
print "You shoot him in the eye, he falls down and dies. You grab the key, and return."
key1 = True
main_hall("not_empty")
else:
print die("You die.")
main_hall("not_empty")
Any suggestions for different ways to 'save' this key across functions, besides making them global?
If you want some variable or variables to be shared between functions, there are a few ways to do it:*
Pass each variable's value into every function as an argument, and return it from every function as part of a return tuple.
Wrap all of the values up in some structure, like a dict that you can look each thing up in by name, so you only have one value to pass and return.
Make the values attributes of an object, and turn the functions into methods of that object's type.
Use a closure, which I won't bother to explain because I'm sure you haven't learned about closures yet.
Use globals.
The Pythonic way to do this is definitely #3, but you haven't learned about classes yet. In that case, I'd just use #5, as you're already doing.
And when you learn about classes, coming back and modifying this script to use a class instead will be a great exercise.
* In fact, under the covers, options 3-5 are all pretty much syntactic sugar for option 2… but don't worry about that.
You could make your key datatype a list or a dict and pass the key list/dict into each key-changing function. Since lists and dicts are mutable, changes made to the key list/dict in one function will be seen in the calling scope and in any subsequent functions that key is passed to.

Why is an indeterminate state of existence of a variable bad programming?

And more to the point, how do I avoid it?
See the link below for further reference; specifically the reply by paxdiablo.
How do I check if a variable exists?
As you probably guessed, I have a scenario where I've programmed a web page that has a variable whose existence is unknown at run time.
What is happening is, a user uploads information that can be in several different formats. To be more concrete, an address. For example, the street may have a directional (southwest, north), and the address may have a condo qualifier (unit#2F). These (or things/scenarios like them) will be assigned to and represented by different variables. As the data is manipulated in my code, I have conditionals
if street_dir_var:
#do something
Hence my question(s): why is this bad form, and whats a proper substitute?
PS - if it matters, I'm coding in Python
Conditionals are fine. The issue is if street_dir_var is not even defined, that line will throw a NameError. You can technically catch NameError, but that makes for messy unmaintainable code. It also suggests that you are putting data into your variable names, which is a bad code smell.
In general, a variable should be defined in any logical branch that tries to access it. If it "doesn't apply" for whatever reason, it should at very least be None. This serves as a fine default value for your variables, and often serves as a default for keyword arguments which need one.
To get more specific here:
These (or things/scenarios like them) will be assigned to and
represented by different variables.
Really bad code smell. All those variables represent data for a single address - you need to aggregate all those variables into a single variable, be it a class, a list, a dict, or a namedtuple.
class Address:
def __init__(self, **kwargs):
self.street = kwargs.get('street')
self.directional = kwargs.get('directional')
self.condo = kwargs.get('condo')
user_data = parse_data(some_data_source) # user_data looks like a dict
address = Address(**user_data)
One address, one container. address.condo might be None, but at least it's defined when I ask for it.

Is 'input' a keyword in Python?

I'm new to Python. I'm writing some code in Sublime and it highlights the word 'input'
I use it as a variable name and it seems to work, so I wondered whether it may be a keyword in a newer version. (I'm currently using 2.7.5)
No, input is not a keyword. Instead, it is a built-in function.
And yes, you can create a variable with the name input. But please don't. Doing so is a bad practice because it overshadows the built-in (makes it unusable in the current scope).
If you must use the name input, the convention is to place an underscore after it:
input_ = input()
input is not a keyword, it's a function provided by the standard library and included in the builtins module (this module provides globally accessible variables and functions.):
>>> import builtins
>>> input is builtins.input
True
And sure, you can create a variable with the name input. It's perfectly fine for experienced and intermediate users to do so because they can easily figure that the input name has been re-used.
Use the best name for the content/intent you want to convey. If input is the best then use it (provided you don't need the builtin), and don't confuse readers with names like input_ (beginners will wonder whether there's a special meaning to a trailing underscore)
But if you're a beginner please don't re-define builtins, by overshadowing the built-in input (overshadowing a variable makes it unusable in the current scope) you'll end-up with this error when calling input() later on (in the same scope) and you may struggle to figure out why:
TypeError: 'str' object is not callable
Beginners should instead use another name, preferably not input_ because underscores have special meanings in python, as a result other beginners will wonder whether there's a special meaning for that trailing underscore (is it the same or related to leading underscores? or maybe to double underscores?)
In another comment someone stated that it is a bad practice to overshadow variables and he even came up with a convention that he borrowed from another use. After all, if overshadowing variables were a really bad practice, the python language designers wouldn't have allowed it in the first place, but they know and recognize that it has the potential to improve readability, just as it does in other languages. So they allowed it, and it also ease transition to Python from other languages where overshadowing is also allowed like C/C++, Java and even bash.
note: the conventional use for a trailing underscore is where it's impossible to use a name, like the keyword class in Python. Then you'd use class_ (but like I wrote above, it's best to avoid it in Python because underscores can confuse beginners as they can convey special meanings)

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.

Categories

Resources