有几个众所周知的python代码样式规则,它们被认为是默认的,我试图遵循这些规则:
换行,使其不超过79个字符。
保持缩进4个空格。
另一种常见的编程建议是
避免全局变量
换句话说,应该始终使用接受所有变量作为参数的函数,并避免直接从更高范围读取的类似Pascal的过程。
然而,在某些情况下,绝对应该打破其中一些规则。例如,如果涉及具有长参数列表的函数。它们有两个不同的问题:
首先,在严重缩进的区块中,剩下的空间太少了。
def function(variable1, variable2, variable3, variable4, variable5,\
variable6, variable7, variable8, variable9):
return variable1 + variable2 + variable3 + variable4 + variable5 +\
variable6 + variable7 + variable8 + variable9
def...
for variable1...
if variable 2...
while variable3...
if variable4...
for variable5...
...
variable10 =\
function(\
variable1,\
variable2,\
variable3,\
variable4,\
variable5,\
variable6,\
variable7,\
variable8,\
variable9)
...
这里作为闭包的程序虽然被认为是一种不好的做法,但可能会有所帮助:
def...
def procedure():
variable10 = variable1 + variable2 + variable3 + variable4 +\
variable5 + variable6 + variable7 + variable8 + variable9
for variable1...
if variable 2...
while variable3...
if variable4...
for variable5...
...
procedure()
...
另一个问题(实际上是特定于python的)是性能。如果有很多功能参数的复制可能会变得非常昂贵:
import time
var1 = 1
var2 = 2
var3 = 3
var4 = 4
var5 = 5
var6 = 6
def function(var1, var2, var3, var4, var5, var6):
pass
def procedure():
pass
starttime = time.time()
for i in range(10000000):
function(var1, var2, var3, var4, var5, var6)
finishtime = time.time()
print('Classical function runtime: {:.3f} s'.format(finishtime - starttime))
starttime = time.time()
for i in range(10000000):
procedure()
finishtime = time.time()
print('Procedure runtime: {:.3f} s'.format(finishtime - start time))
输出:
Classical function runtime: 2.447 s
Procedure runtime: 1.180 s
因此,我向经验丰富的开发人员提出的问题是:
是否有一些东西可以证明使用类似Pascal的程序而不是经典函数,或者应该不惜一切代价避免使用它们,即使它们导致代码更庞大和更慢?
修改
使用*args
和**kwargs
只能部分解决问题,因为在函数调用期间仍需要列出所有参数。此外,它还没有解决性能问题,因为参数仍然被复制。如评论中所提出的,itertools
也并非总是适用。在某些情况下,解析嵌套非常棘手(考虑下面的代码)并且需要花费大量的开发时间,可能会导致代码非常混乱。
def my_function(**kwargs):
with open(kwargs['file_a'], 'r') as input1:
for line1 in input1:
if kwargs['number'] % 3 == 0:
if kwargs['number'] % 9 == 0:
with open(kwargs['file_0'], 'r') as input2:
for line2 in input2:
if line1.startswith('#'):
if line2.startswith('A'):
with open('output.txt') as output1:
for item in kwargs['items']:
if item is in kwargs['good']:
for sub in item:
if sub < 0:
result = process_vars(
kwargs['var1'],
kwargs['var2'],
kwargs['var3'],
kwargs['var4'],
kwargs['var5'],
kwargs['var6'],
kwargs['var7'],
kwargs['var8'],
kwargs['var9'],
kwargs['var10'])
output1.write(result)
elif sub >= 0 and sub < 1:
output1.write('hello')
else:
output1.write('byebye')
elif len(item) > 20:
item = item[: 20]
else:
output1.write(line2)
elif line2.startswith('B'):
print('warning')
else:
print('error')
elif line1.startswith('!'):
kwargs['wonders'].count += 1
else:
kwargs['threats'].append(line1)
else:
kwargs['exceptions'].append(line1)
elif kwargs['number'] % 3 == 1:
with open(kwargs['file_1'], 'r') as input2:
...
elif kwargs['number'] % 3 == 2:
with open(kwargs['file_2'], 'r') as input2:
...
答案 0 :(得分:0)
有人在评论中已经提到过:如果您有两个或更多嵌套for循环,请尝试使用itertools.product()
。
如果无法完成上述操作,至少可以减少if
语句导致的缩进级别。例如:
for abc in ..
if (condition):
for xyz in ...
可以更改为:
for abc in ...
if not (condition):
continue
for xyz in ...
如果有许多参数要传递给方法,请尝试使用*args
(元组中的所有参数)或**kwargs
(字典中的所有参数)。
编辑: 根据您的具体要求,我编辑了给定的代码。这可能不会产生与你的完全相同的结果,但会让你大致了解如何实现上述3点。
def my_function(**kwargs):
process_var_list = ['var1', 'var2', 'var3', 'var4', 'var5', 'var6',
'var7', 'var8', 'var9', 'var10']
#Open all 3 files at one go. This will improve performance and reduce nested loops
with open(kwargs['file_a'], 'r') as input1, open(kwargs['file_0'], 'r') as input2, open('output.txt') as output1:
#following point 1
for line1, line2, item in itertools.product(input1, input2, output1):
if kwargs['number'] % 9 == 0:
#following point 2
if line1[0] not in ["#", "!"]:
kwargs['threats'].append(line1)
continue
elif line1.startswith('!'):
kwargs['wonders'].count += 1
continue
if line2[0] not in ['A', 'B']:
print('error')
continue
elif line2.startswith('B'):
print('warning')
continue
if item in kwargs['good']:
for sub in item:
if sub < 0:
var_args = {var: kwargs[var] for var in process_var_list}
#following point 3
result = process_vars(**var_args)
output1.write(result)
elif 1 < sub >= 0:
output1.write('hello')
else:
output1.write('byebye')
elif len(item) > 20:
item = item[: 20]
else:
output1.write(line2)
elif kwargs['number'] % 3 == 0:
kwargs['exceptions'].append(line1)
elif kwargs['number'] % 3 == 1:
with open(kwargs['file_1'], 'r') as input2:
pass
elif kwargs['number'] % 3 == 2:
with open(kwargs['file_2'], 'r') as input2:
pass