How to rewrite the code more elegantly [closed] - python

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 6 years ago.
Improve this question
The code below reads lines from a file, then it executes the custom function (My_Function) and return values to the variables(e.g. condition_A)
for line in input_file:
if condition_A:
condition_A = My_Function(A_tuple[0], B_tuple[0])
if condition_B:
condition_B = My_Function(A_tuple[1], B_tuple[1])
if condition_C:
condition_C = My_Function(A_tuple[2], B_tuple[2])
if condition_D:
condition_D = My_Function(A_tuple[3], B_tuple[3])
if condition_E:
condition_E = My_Function(A_tuple[4], B_tuple[4])
...
My question is: can the code be modified to more elegant version? After all, many code is similar(I don't want to define another function to simplify it because the code is still similar after the new function is defined). thanks.

Instead of having 5 variables condition_*, use a list, conditions:
conditions=[1]*5 # initialize conditions as you wish
for line in input_file:
for i,condition in enumerate(conditions):
if condition:
conditions[i]=My_Function(A_tuple[i],B_tuple[i])

What about something like
conditions = [condition_A, condition_B, condition_C, condition_D, condition_E]
condition_test = lambda c, i: My_Function(A_tuple[i], B_tuple[i]) if c else c
for line in input_file:
conditions = [condition_test(c, i) for i, c in enumerate(conditions)]

'line' is not referenced in teh loop, is that an error in simplifying it for posting?
How about
condition=1 #or 2 or...
for line in input_file:
My_Function(A_tuple[condition],B_tuple[condition])

Before refactoring your code on a purely syntactic level (which is covered in examples above), it might be useful to evaluate what you're doing with the code on a functional level
Check out your condition_x variables. I think you might be using the same variable for two different things (both type-wise and logically) - usually a bad idea in a weakly typed language. It looks to me as if the user sets a condition to true or false, and then that condition is assigned the output - is the output boolean? is it related to the original value of that variable? Rethinking this might lead to more understandable code.
It is also difficult to evaluate how this can be refactored without seeing what goes in to condition_x - since these might have commonalities.

One more sample(not solution) based on unutbu's:
data = [1,2,3,'',4,5,6, '', 0]
for i in (i for i in xrange(len(data)) if data[i] not in ['',0]):
data[i] += 1
Sorry if duplicate

Here is a generic solution where you can have custom index and you can also access conditions by name if need be and it can be easily extended to add any new complexities
class Condition(object):
def __init__(self, active, index1, index2):
self.active = active
self.index1 = index1
self.index2 = index2
conditions = {
'A': Condition(True,0,0),
'B': Condition(True,1,1),
'C': Condition(True,2,2),
'D': Condition(True,3,3),
'E': Condition(True,4,4),
}
for line in input_file:
for condition in conditions.itervalues():
if condition.active:
condition.active = My_Function(A_tuple[condition.active.index1], B_tuple[condition.active.index2])

Related

Eliminate Indentations in Python

I'm using the Google Docs API to retrieve the contents of a document and process it using Python. However, the document is of complex structure and I have to loop through multiple nodes of the returned JSON, so I have to use multiple for loops to get the desired content and do the filter necessary. Is there a way that I can eliminate some of the indentations to make the format look much more organized?
Here is a snippet of my loops:
for key, docContent in docs_api_result.json().items():
if key == "body":
content = docContent['content']
for i, body_content in enumerate(content):
if "table" in body_content:
for sKey, tableContent in content[i]['table'].items():
if sKey == "tableRows":
for tableRowContent in tableContent:
for tableCellMain in tableRowContent['tableCells']:
for tableCellContent in tableCellMain['content']:
hasBullet = False
for tableCellElement in tableCellContent['paragraph']['elements']:
if "bullet" in tableCellContent['paragraph']:
...
I know that instead of having
if True:
# some code here
I can replace it with
if False:
continue
# some code here
to remove some of the indents, but that only solves part of the problem. I still have 7 for-loops left and I hope that I could remove some of the indentations as well.
Any help is appreciated! :)
The general method for reducing indentation levels would be to identify blocks of code to go in their own functions.
E.g. looking at your loop, I guess I would try something like:
class ApiResultProcessor(object):
def process_api_result(self, api_result):
doc_dict = api_result.json()
if "body" in doc_dict:
self.process_body(doc_dict["body"])
def process_body(self, body_dict):
content = body_dict["content"]
for i, content_element_dict in enumerate(content):
if "table" in content_element_dict:
self.process_table(content_element_dict["table"])
...
def process_table(self, table_dict):
for tableRowContent in table_dict["tableRows"]:
for tableCellMain in tableRowContent["tableCells"]:
for tableCellContent in tableCellMain['content']:
self.process_cell_content(tableCellContent)
def process_cell_content(self, table_cell_dict):
hasBullet = False
for tableCellElement in table_cell_dict["paragraph"]["elements"]:
if "bullet" in table_cell_dict["paragraph"]:
...
The only refactoring that I have done is trying to avoid the dreadful "for if" antipattern.
I am not that experienced with python, but I am pretty sure you can use only one space and not multiple of four every indentation and it won't be an indentation error. Although it is not according to the PEP 8 protocol...
So just remove every 4 spaces/tab you have in this bunch of code, to 1 space.

want to print a line and next when match found-python [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have a variable called message.
that variable has value like below:
:1A:name
:1B:Address
:1C:phone
:2A:/256789422254
TEST VALUE
:2B:/INSTITUTION
from above variable I want to take only :2A: field contains value
which means I wants only below two line
:2A:/256789422254
TEST VALUE
I tried with
lines = message.readlines()
for index,line in enumerate(lines):
if :2A: in line:
print lines [index+2]
which is not working.
Try this:
s = '''
:1A:name
:1B:Address
:1C:phone
:2A:/256789422254
TEST VALUE
:2B:/INSTITUTION
'''
x, y = s[s.index(':2A:') - 1 :].strip().split("\n")[:2]
x = x.split(':')[2]
print(x, y)
Output:
/256789422254 TEST VALUE
message=""":1A:name
:1B:Address
:1C:phone
:2A:/256789422254
TEST VALUE
:2B:/INSTITUTION"""
def solver(lines):
x, y = 0, 0
for i, line in enumerate(lines):
if line.find(':2A:') == 0:
x = i
if line.find(':2B:') == 0:
y = i
break
return lines[x:min(x + 2, y)]
solver(message.split('\n'))
#Output [':2A:/256789422254', 'TEST VALUE']
The solution works by finding the index of ':2A' in the array of lines. It also finds the position of ':2B' in the array. Then it merely returns a slice of the lines in between.

ValueError when splitting lines in a text file [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'd like to split each line of a text file into two by " - ", but I keep getting this error:
File "quiz.py", line 21, in Vocab
questions, answers = line.split("-")
ValueError: too many values to unpack (expected 2)
I'm quite new to coding and could use some help. All tips are welcome as well!
import hashlib
testFile = ""
def qSearch():
options = input ("Vocab/Grammar/or Special? (v/g/s)")
if options == "v":
testFile = "Vocabtest"
Vocab()
elif options == "g":
Grammar()
testFile = "Grammartest"
elif options == "s":
Special()
testFile = "Specialtest"
else:
qSearch()
def Vocab():
with open('Vocabtest.txt','r') as f:
for line in f:
questions, answers = line.split("-") ### error
print (questions)
qSearch()
The text in my text file is formatted like so:
Magandang umaga - Good Morning
Magandang hapon - Good Afternoon
Magandang gabi - Good evening
Magandang umaga sa’yo - Good Morning to you
Magandang hapon din sa’yo - Good Afternoon to you to
"Unpacking" is the name for what you're doing when you write
value1, value2 = a_list
When you do an assignment like that, you're implicitly making an assumption about how many values are contained in a_list -- here it's 2. If there's more or less than 2, there's no good way to give value1 and value2 values without doing very surprising and unhelpful things (like leaving one empty, or leaving some elements of the list unassigned).
So too many values to unpack means that there's at least one line in your file where line.split('-') results in more than 2 elements -- that is, there's at least one line with more than one -.
The problem is because on line 21 in your input text (.txt) file you have more than one - but you only expect one.
A safer way to do it would be to only split once:
questions, answers = line.split("-", 1)

name.replace xX with y if x exists [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
To be more specific I'd like to figure out how to:
name.replace xX with y if x exists, if not then just replace X
I've searched this forum for an hour now, make it two, and all I find is how to replace one thing with another, which by now is pretty easy.
/a
you can just run:
output = name.replace('xX','y').replace('X','y')
Example:
name = "123xX345X"
output = "123y345y"
Sounds like a job for regular expression x?X:
>>> import re
>>> text = " test xX blabla"
>>> re.sub('x?X', 'y', text)
' test y blabla'
>>> text = " test X blabla"
>>> re.sub('x?X', 'y', text)
' test y blabla'
Quote from docs about ? mark:
The question mark character, ?, matches either once or zero times; you
can think of it as marking something as being optional. For example,
home-?brew matches either homebrew or home-brew.
if 'x' in name:
name = name.replace('xX','y')
else:
name = name.replace('X','y')
From your example above this is a slightly more involved problem. You have to make sure to do your renames in the root namespace or things can get nasty. You also run the risk of renaming parents before children, which will make it hard to get at the children with one call to ls. So:
def replace_with_any_namespace(src, tgt):
cmds.namespace(set=":")
results = {}
xforms = cmds.ls(r=True, tr=True, l=True) # use long paths and recursive to get all namespaces
xforms = [i for i in xforms if src in i] # only work on items with your target pattern
xforms.sort()
xforms.reverse() # sort and reverse means children get renamed before parents
for item in xforms:
path, sep, shortname = item.rpartition("|") # gets only the last name
newname = shortname.replace(src, tgt) # this should be fine even if the namespace is there
results[item] = cmds.ls(cmds.rename ( item, newname), l=True)[0]
# the paths and returns are all long paths so there are no ambiguities
return results
Are you trying to move things out of their namespaces with this? Thats easier:
cmds.namespace(mv = ("R", ":"), force=True)
which moves everything in R:* to the base namespace. This will probably result in some renames, however. You might want to put important nodes into a set before you call this so you can find them.

Selecting from multiple variables

I am attempting to find objects on the screen, see if they exist, and if so, select them. Using the Sikuli library to run this little automation.
while True:
if exist("image/one.png", "image/two.png", "image/three.png"):
click ("image/one.png", or "image/two.png", or "image/three.png")
break
I get SyntaxError: mismatched input 'or' expecting RPARENa I've done a quick search but there is nothing I saw relevant to my particular issue.
I've even tried
while True:
if exist("image/one.png", or "image/two.png", or "image/three.png"):
click ("image/one.png", or "image/two.png", or "image/three.png")
break
And that results in the same error.
#Stephan: New code snippet with error.
class gameImages():
imageFiles = ["one.png", "two.png", "three,png"]
for imageFile in imageFiles:
if exists(imageFile):
click(imageFile)
The Error now, :
NameError: name 'imageFiles' is not defined
for imageFile in imageFiles:
if exists(imageFile):
click(imageFile)
Your while loop isn't doing anything, and neither is your break statement. This might do what you want, assuming I understand what you want to do.
After reading a little of the Sikuli docs, I think this might also do what you want.
for impath in ("image/one.png", "image/two.png", "image/three.png"):
match = exists(impath)
if match:
click(match.getTarget())
Even easier, this is a perfect use of filter(ifexist,imageFiles). You then know that all >=0 elements in the return of filter can be used :). And it's more concise and clearly conveys your intent - much nicer to read then a chain of for's and if's
a = range(10)
# [1,2,3,4,5,6,7,8,9]
print filter(lambda x: x > 5, a)
# [6,7,8,9]
Also the or is a logical operator:
e.g.
a = 5
b = 6
c = 5
if( (a==c) or (b==c) ):
print 'c is repeated'
# c is repeated
your use of the or here makes no sense as it doesn't have operands to operate on - these can even be two objects, e.g.
1 or 2 since anything can be cast to a boolean
a concise way to do what you want is:
//imagepaths = your list of imagepaths
map(lambda x: click(x.getTarget()), filter(exists, imagepaths))

Categories