Ho can this code be optimized?
Maybe it is possible to write it shorter, make it more 'pythonic'?
...
check_pass = 0
if key == 'media':
size_check_pass = 0
if some_check_func(xxx): size_check_pass = 1
...
format_checks_pass = 0
if...some_checks... : format_checks_pass = 1
if size_check_pass and format_checks_pass: check_pass = 1
if key == 'text':
line_end_check_pass = 0
if (((some checks))): line_end_check_pass = 1
lenght_check_pass = 0
if len(file) < 1000: lenght_check_pass = 1
if line_end_check and lenght_check_pass: check_pass = 1
if check_pass:
...
The background of the code is to check each file type for different conditions.
You could use a dictionary as a sort of dispatch table perhaps. Something like
def media_checks(f):
...
return pass
def text_checks(f):
...
return pass
_dispatch = {}
_dispatch['media'] = media_checks
_dispatch['text'] = text_checks
dispatch_func = _dispatch[key]
check_pass = dispatch_func(your_file)
This would split you code up so it is easier to read and maintain. It also isolates the code for checking each file type in an individual function.
First, for your first if, your code suffers from conditional complexity code smell. You can fix with inline method refactoring: you don't need your size_check_pass and format_checks_pass booleans, and can evaluate both conditions directly in the final if statement, with if ...some_checks... and some_check_func(xxx) instead of if size_check_pass and format_checks_pass. which gives you
check_pass = 0
if key == 'media':
if ...some_checks... and some_check_func(xxx):
check_pass = 1
Then, do this for the second if also. And you don't want to check if key = 'text' if you had already that key = 'media', so in the end
check_pass = 0
if key == 'media':
if some_check_func(xxx)and ...some_checks...:
check_pass = 1
else if key == 'text':
if (((some checks)))and len(file) < 1000:
check_pass = 1
if check_pass:
...
So you always have a sequence of checks.
First, you can shorten your conditions:
...
check_pass = False # to make it more boolean
if key == 'media':
size_check_pass = some_check_func(xxx)
format_checks_pass = ...result of your checks...
check_pass = size_check_pass and format_checks_pass
if key == 'text':
line_end_check_pass = (((some checks)))
length_check_pass = len(file) < 1000
check_pass = line_end_check and length_check_pass
if check_pass:
...
or compress them even more:
...
check_pass = False # to make it more boolean
if key == 'media':
check_pass = some_check_func(xxx) and ...result of your checks...
if key == 'text':
check_pass = (((some checks))) and len(file) < 1000
if check_pass:
...
And then you could apply a system like the one from jamesj, but maybe with lists of conditional expressions:
def some_checks():
...
return True or False
def other_checks(f):
...
return ...
_dispatch = {
'media': [lambda: some_check_func(xxx), some_checks],
'text' : [other_checks, lambda: len(file) < 1000]
}
dispatch_list = _dispatch[key]
check_pass = all(func() for func in dispatch_list)
Related
The example of too-many-return-statements is as above, but my scenario is as follows, how to make the function more beautiful?
def func():
# do something1
ret1 = do_something1()
if ret1 != 0:
return ret1
# do something2
ret2 = do_something2()
if ret2 != 0:
return ret2
# ......
return 0
You could try something like this:
def foo(x):
nums = ['one','two','three','four','five','six','seven']
return 'This is ' + nums[x-1]
to solve your example. And you could solve your scenario like this:
def func():
functions = [do_something1,do_something2,...]
for function in functions:
ret = function()
if ret != 0:
return ret
return 0
Check out this example.
It converted:
def func(x):
if x == 1:
return "hi1"
if x == 2:
return "hi2"
if x == 3:
return "hi3"
if x == 4:
return "hi4"
if x == 5:
return "hi5"
if x == 6:
return "hi6"
if x == 7:
return "hi7"
to:
d = {1: "hi1", 2: "hi2", 3: "hi3", 4: "hi4", 5: "hi5", 6: "hi6", 7: "hi7"}
def func(x):
return d[x]
Just to silence it another option is:
def func(x):
if x == something1:
res = "something1"
elif x == something2:
res = "something2"
elif x == something3:
res = "something3"
elif x == something4:
res = "something4"
elif x == something5:
res = "something5"
elif x == something6:
res = "something6"
elif x == something7:
res = "something7"
else:
res = "default"
return res
You can also silence it in settings.json file if you think it's too strict rule which I think it is:
"python.linting.pylintArgs": [
"--disable=R0911"
],
def func():
res = default_res
if foo:
res = res_foo
elif bar:
res = res_bar
return res
I recommend doing it this way
Using some form of lookup is the way to handle this. A dictionary is a good general purpose idea. A list is useful when the lookup 'key' is an integer.
HOWEVER
When using a lookup technique you have to consider that your 'key' may not be available. If your dictionary (for example) has 7 integer keys (1->7 inclusive) and your function is passed a value of 8, what are you going to do? You could allow the exception and deal with that separately or you need to avoid an exception and return some default value, perhaps implicitly.
In general you can use the proposed solution by pylint documentation:
https://pylint.pycqa.org/en/latest/user_guide/messages/refactor/too-many-return-statements.html
But IMHO in some case it's impossible to use.
I don't kwonw your specific case, but you can disable pylint in a specific line of code using a comment like this.
def func(): #pylint: disable=R0911
# do something1
ret1 = do_something1()
if ret1 != 0:
return ret1
# do something2
ret2 = do_something2()
if ret2 != 0:
return ret2
# ......
return 0
My code:
test_str = '''
(()(code)())
((t(e(x(t(()
()(co)de)('''
countofrightbrackets = 0
countofleftbrackets = 0
blockcount = 0
myDict = {};
for i in test_str:
if i == '(':
countofrightbrackets = countofrightbrackets + 1
if i == ')':
countofleftbrackets = countofleftbrackets + 1
if i == '':
blockcount = blockcount + 1
if countofrightbrackets == countofleftbrackets:
myDict.update({blockcount:'True'});
else:
myDict.update({blockcount:'False'});
print (myDict)
My program is counting () and if count of ( = ) then save to dictionary True. Else false. In test_str I have some blocks - they are dissociated with 2 new rows. In if i == '': I want to show, that if I = 2 new rows, then compete the code. Also I need to check are brackets are at correct positions - like ()()() is true and ())( is false. How to do this?
Example:
Input:
(()()())
((((((()
()())(
Output:
1: True 2: False 3: False
i have 4 variables here that needs to check whether its true or false. together will all the combinations.. 4 true, 3 true 1 false, 2 true 2 false, 1 true 3 false and all false.. in total this will make like 10++ condition (a bit lazy to count).
if game and owner and platform and is_new and for_sale:
game_copy = GameCopy.objects.all()
elif game:
game_copy = GameCopy.objects.filter(game=game)
elif platform:
game_copy = GameCopy.objects.filter(platform=platform)
elif owner:
game_copy = GameCopy.objects.filter(user=owner)
elif is_new:
game_copy = GameCopy.objects.filter(is_new=is_new)
elif for_sale:
game_copy = GameCopy.objects.filter(for_sale=for_sale)
else:
game_copy = GameCopy.objects.all()
return game_copy
im looking for a leaner approach for this condition.. hopefully ended with something with 5 to 10 lines
You could add everything that's truthy to a dictionary and then pass those to the function by unpacking keyword arguments.
args = { "game": game, "owner": owner, "platform": platform, "is_new": is_new, "for_sale": for_sale }
# check if all args are truthy
all_args = all(v for v in args.values())
# filter out only the truthy args
filtered_args = {k: v for k, v in args.items() if v}
if all_args or not filtered_args:
# if all_args is true or filtered_args is empty
game_copy = GameCopy.objects.all()
else:
# Unpack filtered_args into filter()
game_copy = GameCopy.objects.filter(**filtered_args)
You could change your variable to a set of flags (bits set in a unique integer)
GAME = 1 << 0 # 1
OWNER = 1 << 1 # 2
PLATFORM = 1 << 2 # 4
IS_NEW = 1 << 3 # 8
FOR_SALE = 1 << 4 # 16
# for instance flags = GAME
# or flags = OWNER | IS_NEW
# ensures that there is only one flag set and pass it to you filter
if (flags & (flags-1) == 0) and flags != 0:
game_copy = GameCopy.objects.filter(flags)
# Otherwise
else: game_copy = GameCopy.objects.all()
return game_copy
Write a python function, check_anagram() which accepts two strings and returns True, if one string is an anagram of another string. Otherwise returns False.
The two strings are considered to be an anagram if they contain repeating characters but none of the characters repeat at the same position. The length of the strings should be the same.
Note: Perform case insensitive comparison wherever applicable.
This is my code:
def check_anagram(data1,data2):
first = data1.lower()
second = data2.lower()
d1 = []
d2 = []
for i in range(0, len(first)):
d1.append(first[i])
for i in range(0, len(second)):
d2.append(second[i])
for_check1 = sorted(d1)
for_check2 = sorted(d2)
if (for_check1 != for_check2):
return False
count = 0
if (len(d1) == len(d2)):
for i in d1:
for j in d2:
if(i == j):
a = d1.index(i)
b = d2.index(j)
if(a == b):
return False
else:
count += 1
if(count == len(first)):
return True
else:
return False
print(check_anagram("Schoolmaster", "Theclassroom"))
The output I am getting is "False"
Although this program is giving relevant output for string values like {silent, listen}{Moonstarrer, Astronomer}{apple, mango} but not for the above two strings(in code)
What cases am I missing in this code?? How to rectify this thing?
Your function could be simplified as:
def check_anagram(data1, data2):
data1 = data1.lower()
data2 = data2.lower()
if sorted(data1) != sorted(data2):
return False
return all(data1[i] != data2[i] for i in range(len(data1)))
Which actually works for the case you specified.
your code is correct just write len(second) instead of count.
def check_anagram(data1,data2):
first = data1.lower()
second = data2.lower()
d1 = []
d2 = []
for i in range(0, len(first)):
d1.append(first[i])
for i in range(0, len(second)):
d2.append(second[i])
for_check1 = sorted(d1)
for_check2 = sorted(d2)
if (for_check1 != for_check2):
return False
count = 0
if (len(d1) == len(d2)):
for i in d1:
for j in d2:
if(i == j):
a = d1.index(i)
b = d2.index(j)
if(a == b):
return False
else:
count += 1
if(len(second) == len(first)):
return True
else:
return False
print(check_anagram("Schoolmaster", "Theclassroom"))
This program of mine is clearing all possible test cases.
def check_anagram(data1,data2):
data1=data1.lower()
data2=data2.lower()
if(len(data1)==len(data2)):
if(sorted(data1)!=sorted(data2)):
return False
else:
if(data1[i]!=data2[i] for i in range(len(data1))):
return True
else:
return False
else:
return False
print(check_anagram("eat","tea"))
I am struggling with the logic for the problem below and I know that even if I nailed the logic, I would probably implement it clumsily, so any advice would be awesome.
I have a dictionary representing a file:
the_file = {'Filename':'x:\\myfile.doc','Modified':datetime(2012,2,3),'Size':32412}
I have a list of filters and I want to filter the file dictionary to determine a match.
filters = [
{'Key':'Filename','Criteria':'Contains','Value':'my'},
{'Key':'Filename','Criteria':'Does not end with','Value':'-M.txt'},
{'Key':'Modified','Criteria':'After','Value':datetime(2012,1,1)}
]
My best attempt at creating a function to do this (which doesn't work):
def is_asset(the_file, filters):
match = False
for f in filters:
if f['Key'] == u'Filename':
if f['Criteria'] == u'Contains':
if f['Value'] in the_file['Filename']:
match = True
elif f['Criteria'] == u'Starts with':
if the_file['Filename'].startswith(f['Value']):
match = True
elif f['Criteria'] == u'Ends with':
if the_file['Filename'].endswith(f['Value']):
match = True
elif not f['Criteria'] == u'Does not end with':
if the_file['Filename'].endswith(f['Value']):
match = False
elif f['Criteria'] == u'Equals':
if os.path.basename(the_file['Filename']) == f['Value']:
match = True
elif f['Criteria'] == u'Does not contain':
if f['Value'] in the_file['Filename']:
match = False
elif f['Key'] == u'Modified':
mtime = int(os.path.getmtime(the_file['Filename']))
if f['Criteria'] == u'Before':
if f['Value'] > datetime.fromtimestamp(mtime):
the_file['Modified'] = mtime
match = True
elif f['Criteria'] == u'After':
if f['Value'] < datetime.fromtimestamp(mtime):
the_file['Modified'] = mtime
match = True
elif f['Key'] == u'Size':
size = long(os.path.getsize(the_file['Filename']))
if f['Criteria'] == u'Bigger':
if f['Value'] < size:
the_file['Size'] = size
match = True
elif f['Value'] > size:
the_file['Size'] = size
match = True
if match:
return the_file
Instead of trying to do it in one megafunction, break it down into smaller steps.
filenamecondmap = {
u'Contains': operator.contains,
u'Does not end with': lambda x, y: not x.endswith(y),
...
}
...
condmap = {
u'Filename': filenamecondmap,
u'Modified': modifiedcondmap,
...
}
And then walk the structures until you have the conditional, then execute it.
condmap[u'Filename'][u'Contains'](thefile['Filename'], 'my')
You can simply use functions as your 'criteria'. This makes it much simpler, as you don't have to write a big if-else ladder. Something like this:
def contains(value, sub):
return sub in value
def after(value, dt):
return value > dt
filters = [
{'Key': 'FileName', 'Criteria': contains, 'Value': 'my'},
{'Key': 'Modified', 'Criteria': after, 'Value': datetime(2012,1,1)}
]
for f in filters:
if f['Criteria'](filename[f['Key']], f['Value']):
return True