proper way to name a variable already used? - python

in python (3.3.3), what is the proper way to name a variable that is already being used?
for example, I want to create the variable input. obviously this will not work as there is a python keyword called input.
assuming I needed a name similar to input, what is the proper way to name it without deviating much from the word input, that is, not using a name like user_input or answer?

You can use any name even if it is used by a function.
What you can't is use keywords like def, class, if, else...
But of course it is not a good practice to replace those names used by functions to avoid confusion.
A known practice is to add a _ to the end: input_, class_...

Related

when should I make a function that has parameters / arguments?

when should we actually create a function that has parameters / arguments?
today I made a programming project. Then it occurred to me when should I actually create a function that has parameters .. I usually create it when there is a global value / variable and that value must exist in some function then I make that value the argument of the function .. did I do it right? or wrong? if wrong what are the best practices for doing it?
varGlobal = "test"
def foo():
print(varGlobal)
# or
def foo(parm):
print(parm) # parm -> varGlobal
def foo():
ask = input("ask")
print(ask)
# or
def foo(parm):
print(parm) # parm -> global user input
It's usually a good idea to use parameters. Consider what the purpose of the function is. Parameterized functions are more generally useful than non-parameterized functions.
If the first case, is whatever foo does applicable only to a single value, or could it be useful for arbitrary values, regardless of what variable might refer to them? In the former case, you are stuck using varGlobal. In the latter, the call can always use foo(varGlobal) if that's the necessary argument.
In the second, might foo be useful to someone who already has a value, and doens't need to call input? In the former case, you are stuck calling input. In the latter, the caller can always use foo(input()) or the like if they really need to call input.
I would strongly suggest that you should use parameters and arguments in every function. it simply makes the whole process of design simpler.
You can clear see what data the function uses, and what it returns.
The only use of global values (either module globals, or globals imported from other modules are :
Module or application wide constants
Module or application wide function or classes (which are in Python efectively module level 'globals'.
Your functions should always return values and never change a global value (by definition if you stick to the above list that you wont be changing anything).
In my opinon using the 'global' keyword is never needed (in 8 years of coding I have never needed it, or identified a reason to use it).
Using global variables is bad practice in any language GlobalVariablesAreBad
Global variables can be used if you need to access or modify the variable in several methods/classes in the same module.
Remember you need to point global my_global_variable to modify the variable.
Parameters are variables needed in the method to do the processing. These variables should live locally in the method. If you need to retrieve something from the method, you should add a return statement. Also, if you need to return several variables you can return as tuple.
So, in this way, you're organizing your code, making all variables visible to other people. Also I recommend you to use docstrings to fully document your methods, variables and processing.
When we need to solve the same sort of question but with different arguments. So you don't have to write the same function over and over again. Let's say you want to write a function that will return the square of the provided number as an argument.
So you write
def square(num):
return num*num
So every time you need to have square of a number..you just put that number in place of the argument and not write the whole function again.

Lookup dynamic dictionary key

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.

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)

Adding variables "by name" to local namespace

I know that I can add a variable to the global namespace "by name" with something like:
def getNewVar(name,val):
globals()[name]=val
The things is, I would like to do this in a local namespace. I have already tried and failed in using locals() instead of globals(). Someone probably wants to know why I would do something like this. OK, in my use case, the argument to the function is actually a dictionary, and I would like to do something like:
def processDictEntries(dict):
for varname in dict.keys():
locals()[varname]=dict[varname] # won't work, of course
This way, further down in the function, I won't have to keep typing
result1=dict['var1']+5.
result2=dict['var2']*dict['var7']
over and over again. I can just type
result1=var1+5
result2=var2*var7
And, if there is a way to do this in a small loop like I have written, then I don't have to do:
var1=dict['var1']
var2=dict['var2'] etc.
either. I'm really just looking for economy of code; it's a big dictionary.
BTW, the entries of the dictionary are never altered; it is strictly input. And, yes, I know that if the input dictionary lacks one of the variables the function needs, I will be in touble, but I think that can be dealt with. Thanks!
If you can change how you call the function:
def processDictEntries(var1=None,var2=None,**kwargs):
#do stuff with var1,var2 ...
And then call the function as:
processDictEntries(**dict)
and of course, if you can't do that, you can always use processDictEntries as a wrapper:
def _processDictEntries(var1=None,var2=None,**kwargs):
...
def processDictEntries(d):
return _processDictEntries(**d)
As a side note, it's not a good idea to name a variable dict as then you shadow the builtin function

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?

Categories

Resources