local variable value is not used - python - python

I am writing some python code (to work in conjuction with ArcGIS), and I have a simple statement that runs fine and does exactly what I am asking it to do, I just get a 'warning' from my scripting software (PyCharm) telling me:
Local variable 'row' value is not used
This inspection highlights local variables, parameters or local functions unused in scope.
I understand it is not used, because it is not needed. This is the only way (that I know of personally) to work out how many rows exist in a table.
Can someone tell me if there is a better (more correct) way of writing this??
cursor = arcpy.SearchCursor(my_table)
for row in cursor:
count += 1
print count
Cheers

By convention if you're looping and don't intend to use the value you store the iterator in a variable named _. This is still a normal variable that gets each value in turn, but is taken to mean "I don't plan to use this value." To use this convention you'd rewrite your code as:
cursor = arcpy.SearchCursor(my_table)
for _ in cursor:
count += 1
print count
See What is the purpose of the single underscore "_" variable in Python? to learn more about the single underscore variable.
But as Markus Meskanen pointed out there is a better way to solve this specific problem.

Related

Why must a variable be declared a global variable before it gets assigned?

Why do we have to do this:
global x
x = "Hello World!"
When this is more readable:
global x = "Hello World"
Why is this, is there a reason behind it?
The goal of Python is to be as readable as possible. To reach this goal the user must be forced act in a clear defined way - e.g. you must use exactly four spaces. And just like this it defines that the global keyword is a simple statment. This means:
A simple statement is comprised within a single logical line.
Simple Statements
And
Programmer’s note: the global is a directive to the parser. It applies only to code parsed at the same time as the global statement.
The global statement
If you would write this:
global x = 5
You would have two logical operations:
Interpreter please use the global x not a local one
Assign 5 to x
in one line. Also it would seem like the global only applies to the current line, and not to the whole code block.
TL;TR
It's to force the user to write better readably code, which is splitted to single logical operations.
The document writes that
Names listed in a global statement must not be used in the same code block textually preceding that global statement.
CPython implementation detail: The current implementation does not enforce the latter two restrictions, but programs should not abuse this freedom, as future implementations may enforce them or silently change the meaning of the program.
As for the readability question, I think the second one seems like a C statement. Also it not syntactically correct
I like to think it puts your focus squarely on the fact that you are using globals, always a questionable practice in software engineering.
Python definitely isn't about representing a problem solution in the most compact way. Next you'll be saying that we should only indent one space, or use tabs! ;-)

Function Call Variables Same as In Function

I am somewhat new to Python--beginner moving to intermediate--and would like to know how more experienced Python coders name their call and function variables.
Specifically, I like to name the call variables the same as the called function's 'receive' variables. Ditto the return variables.
Works fine, but are there problems I could run into, outside of changing a variable to global in the future?
An example call: v_Array = f_InitSpecified2DArray(v_Width,v_Length)
The example called or 'receiving' function: def f_InitSpecified2DArray(v_Width, v_Length):
And I do the same in the return as well: return v_Array
def f_InitSpecified2DArray(v_Width, v_Length):
v_Array = [v_Width, v_Length]
return v_Array
v_Array = f_InitSpecified2DArray(v_Width,v_Length)
The question is: Shall I expect any conflict resulting from reuse of name v_Array inside the function return and later in the calling code, where it goes assigned into variable with the same name v_Array?
Thanks.
No, this will not cause you difficulties, and doesn't cause confusion - for you, your readers, or the Python interpreter. Certainly it's less confusing than making up a new name just to differ from the parameter name, which is unnecessary. In fact, you'll often encounter the same name being used for both a named parameter and its argument, as in
runner = DocTestRunner(verbose=verbose, optionflags=optionflags)
which comes from doctest.py in the standard library (for Python 3.3).
It's instructive to search the standard library for this pattern, <name>=<same_name> (abuse of notation which I'll rectify in a moment), as its occurrences are examples of just what you're asking about. On OS X and Linux, the following command will show all lines in the standard library (plus site-packages) with occurrences of the pattern:
grep -Er --include=*.py '(\b[[:alnum:]]+\b)=\1\b' /path/to/pythonlib
On a Mac, for example, /path/to/pythonlib for Python 3.3 is usually /Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3.
This command shows how many lines feature the construct, many of which have multiple occurrences:
grep -Er --include=*.py '(\b[[:alnum:]]+\b)=\1\b' /path/to/pythonlib | wc -l
I get a count of 1129, which includes a few dozen in my site-packages subdirectory. In other words, it's quite common.
Read PEP 008 titled "Style Guide for Python Code"
You seem to search for something more precise and systematic, this I appreciate, but you will safe a lot of effort and confusion to yourself and others dealing with your code, if you try to folow the PEP 008.
As usual, you will not find it followed everywhere, but that is life.
To your question about function names and variables - PEP 008 recommends using lowercase names with words separated by underscore.
local variable names are irrelevant, it really does not matter what variable name you use for return.
And do not plan moving variables into global scope too early, you shall in fact working in the other direction.

Accessing specific values of a loop-created dictionary in a Python function

I am very new to Python and as an exercise I tried solving a basic finance exercise using code. My objective is to get a dictionary of spot rates and then a dictionary of discount rates calculated from those. I had thought to something like this:
discountrates={}
def discountrates(n):
spotrates={}
for x in range(1,n+1):
spotrates['s'+str(x)]=float(input('What is s'+str(x)+'? (not in percentage)'))
for y in range(1,n+1):
discountrates['d(0,'+str(y)+')']= 1/((1+float(spotrates['s'+str(y)]))**y)
for key, value in discountrates.items():
print (key, value)
Now the problem is that dictionary items cannot be accessed in a function. When I looked in your forum, I found solutions for unpacking the dictionary but that does not work in my case because I need to access a specific element of the dictionary, whose name cannot be fully specified (as I have seen in the Python manual) because it's part of a loop, in order for the formula to work without having to manually insert anything else. I used a dictionary in the first place to create names that were automatically generated but now I can't seem to get the information out of it.
What is the best solution?
Thanks in advance for the help. It's been driving me crazy.
It's because you called your global variable discountratesdict not discountrates (which is the name of your function).
I suggest you don"t name your dictionary like your function since the later will overwrite the former. In line 1 you say discountrates is an empty dict, in line 2 you say discountrates is a function object. You need to give them different names in python if they are on the same scope.
Furthermore why do you need discountrates to be global? would you like to keep old rates if n is smaller than a previous n? For performance I suggest you combine the two loops. Besides that there is no reason why the second loop can't read for x ... as well since zou don't use x anymore anyway. As a further hint, if you come to the conclusion, that a global is the only way it might help to add global discountratesdict, so it is easier to spot that a global is intended here, even though this is not necessary in your particular case since the []-operator needs an object and thus it already refers to your global.
Putting all this together yields:
discountratedict={}
def discountrates(n):
global discountratedict
spotrates={}
for x in range(1,n+1):
spotrates['s'+str(x)]=float(input('What is s'+str(x)+'? (not in percentage)'))
discountratedict['d(0,'+str(x)+')']= 1/((1+float(spotrates['s'+str(x)]))**x)
for key, value in discountratedict.items():
print (key, value)

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?

Correctness about variable scope

I'm currently developing some things in Python and I have a question about variables scope.
This is the code:
a = None
anything = False
if anything:
a = 1
else:
a = 2
print a # prints 2
If I remove the first line (a = None) the code still works as before. However in this case I'd be declaring the variable inside an "if" block, and regarding other languages like Java, that variable would only be visible inside the "if".
How exactly variable scoping works in Python and what's the good way to program in cases like this?
Thanks!
As a rule of thumb, scopes are created in three places:
File-scope - otherwise known as module scope
Class-scope - created inside class blocks
Function-scope - created inside def blocks
(There are a few exceptions to these.)
Assigning to a name reserves it in the scope namespace, marked as unbound until reaching the first assignment. So for a mental model, you are assigning values to names in a scope.
I believe that Python uses function scope for local variables. That is, in any given function, if you assign a value to a local variable, it will be available from that moment onwards within that function until it returns. Therefore, since both branches of your code are guaranteed to assign to a, there is no need to assign None to a initially.
Note that when you can also access variables declared in outer functions -- in other words, Python has closures.
def adder(first):
def add(second):
return first + second
return add
This defines a function called adder. When called with an argument first, it will return a function that adds whatever argument it receives to first and return that value. For instance:
add_two = adder(2)
add_three = adder(3)
add_two(4) # = 6
add_three(4) # = 7
However, although you can read the value from the outer function, you can't change it (unlike in many other languages). For instance, imagine trying to implement an accumulator. You might write code like so:
def accumulator():
total = 0
def add(number):
total += number
return total
return add
Unfortunately, trying to use this code results in an error message:
UnboundLocalError: local variable 'total' referenced before assignment
This is because the line total += number tries to change the value of total, which cannot be done in this way in Python.
There is no problem assigning the variable in the if block.
In this case it is being assigned on both branches, so you can see it will definitely be defined when you come to print it.
If one of the branches did not assign to a then a NameError exception would be raise when you try to print it after that branch
Python doesn't need variables to be declared initially, so you can declare and define at arbitrary points. And yes, the scope is function scope, so it will be visible outside the if.
i'm quite a beginner programmer, but for what i know, in python private variables don't exist. see private variables in the python documentation for a detailed discussion.
useful informations can also be found in the section "scopes and namespaces" on the same page.
personally, i write code like the one you posted pretty much every day, especially when the condition relies in getting input from the user, for example
if len(sys.argv)==2:
f = open(sys.argv[1], 'r')
else:
print ('provide input file')
i do declare variables before using them for structured types, for example i declare an empty list before appending its items within a loop.
hope it helps.

Categories

Resources