我目前在程序中有一些包含15个或更多参数的函数。但是,所有十五个参数都不是同时需要的。
我有一些switch语句函数,使用字典来执行所需的相关功能。我最极端的例子如下:
def Instrument_Type_Calcs_C(InstType_C, raw_data_LP, maxcounts_C, Measurement_Min,
Measurement_Max, Measurement_Type, SG, Tank_Shape, area, dish,
diameter, length, Strapping_Table, Poly_Data, Tank_Number,
LevelOffset):
switcher = {
'8AI': lambda: inst.FourTwenty(raw_data_LP, maxcounts_C, Measurement_Min,
Measurement_Max, Measurement_Type, SG, Tank_Shape,
area, dish, diameter, length, Strapping_Table,
Poly_Data, Tank_Number, LevelOffset),
'Magprobe': lambda: inst.SGMagprobe(raw_data_LP,
Tank_Shape, area, dish, diameter, length,
Strapping_Table, Poly_Data, Tank_Number,
LevelOffset),
'TLS': lambda: inst.TLS(raw_data_LP),
}
return switcher.get(InstType_C, lambda : None)()
现在我已尝试调查*args
和**kwargs
,但我不确定这些是否会对我有所帮助。如果我使用*args
来定义函数,我仍然需要在调用函数时定义所有参数。但是,我需要在if: elif:
语句中使用三个不同的函数调用来声明正确数量的参数。即:
if type == '8AI':
volume = Instrument_Type_Calcs_C(InstType_C, raw_data_LP, maxcounts_C, Measurement_Min,
Measurement_Max, Measurement_Type, SG, Tank_Shape, area,
dish, diameter, length, Strapping_Table, Poly_Data,
Tank_Number, LevelOffset)
elif type == 'Magprobe':
volume = Instrument_Type_Calcs_C(InstType_C, raw_data_LP, SG, Tank_Shape, area, dish,
diameter, length, Strapping_Table, Poly_Data,
Tank_Number, LevelOffset)
elif type == 'TLS':
volume = Instrument_Type_Calcs_C(InstType_C, raw_data_LP)
显然,这只是破坏了switch语句的要点,并且无法解决真正长函数调用的问题。
总的来说,它不会对我的代码造成任何问题,但如果有更好的实现方法,我想了解如何。
答案 0 :(得分:1)
您可以使切换函数接受除第一个参数InstType_C
之外的所有参数,# For testing define and create a class with methods to call.
# Each method will just print out the values of the arguments it was passed.
class Inst(object):
def FourTwenty(self, *args):
print('called FourTwenty({})\n'.format(args))
def SGMagprobe(self, *args):
print('called SGMagprobe({})\n'.format(args))
def TLS(self, *args):
print('called TLS({})\n'.format(args))
inst = Inst() # create instance for testing
# For testing create variables to pass as arguments, each variable will contain
# the variable's name as its value. i.e. some_variable = 'some_variable'.
arguments = [arg.strip() for arg in (
"raw_data_LP, maxcounts_C, Measurement_Min, Measurement_Max, "
"Measurement_Type, SG, Tank_Shape, area, dish, diameter, length, "
"Strapping_Table, Poly_Data, Tank_Number, LevelOffset").split(',')]
for arg in arguments:
globals()[arg] = arg
#### End of testing scaffold.
class AttrDict(dict):
"""Allows use of dot notation to access dictionary's contents."""
def __init__(self, *args, **kwargs):
super(AttrDict, self).__init__(*args, **kwargs)
self.__dict__ = self
def Instrument_Type_Calcs_C(InstType_C, **kwargs):
kwargs = AttrDict(kwargs) # make them easier to access
switcher = {
'8AI': lambda: inst.FourTwenty(kwargs.raw_data_LP, kwargs.maxcounts_C,
kwargs.Measurement_Min,
kwargs.Measurement_Max, kwargs.Measurement_Type,
kwargs.SG, kwargs.Tank_Shape, kwargs.area, kwargs.dish,
kwargs.diameter, kwargs.length, kwargs.Strapping_Table,
kwargs.Poly_Data, kwargs.Tank_Number, kwargs.LevelOffset),
'Magprobe': lambda: inst.SGMagprobe(kwargs.raw_data_LP, kwargs.Tank_Shape, kwargs.area,
kwargs.dish, kwargs.diameter, kwargs.length,
kwargs.Strapping_Table, kwargs.Poly_Data,
kwargs.Tank_Number, kwargs.LevelOffset),
'TLS': lambda: inst.TLS(kwargs.raw_data_LP),
}
return switcher.get(InstType_C, lambda: None)()
volume = Instrument_Type_Calcs_C('8AI', raw_data_LP=raw_data_LP,
maxcounts_C=maxcounts_C, Measurement_Min=Measurement_Min,
Measurement_Max=Measurement_Max,
Measurement_Type=Measurement_Type, SG=SG,
Tank_Shape=Tank_Shape, area=area, dish=dish,
diameter=diameter, length=length,
Strapping_Table=Strapping_Table, Poly_Data=Poly_Data,
Tank_Number=Tank_Number, LevelOffset=LevelOffset)
volume = Instrument_Type_Calcs_C('Magprobe', raw_data_LP=raw_data_LP, SG=SG,
Tank_Shape=Tank_Shape, area=area, dish=dish,
diameter=diameter, length=length,
Strapping_Table=Strapping_Table, Poly_Data=Poly_Data,
Tank_Number=Tank_Number, LevelOffset=LevelOffset)
volume = Instrument_Type_Calcs_C('TLS', raw_data_LP=raw_data_LP)
,关键字参数。这样就可以指定每次调用时要传递的值。
为了说明这一点,我已将其应用于您的示例代码。为了制作实际上可以运行的东西,已添加了许多代码中遗漏的东西,但仅用于测试目的。
这可能使它看起来并没有太大的改进,但那是因为测试时定义了一堆包含自己名字的变量。这使得对切换器功能的调用时间更长,因为每个关键字参数都被赋予了同名变量的值,因此它们的长度是实际操作中的两倍。
所有测试代码都使这看起来很长很复杂,但我希望你可以忽略它,以便了解目标的优点。
您没有遵循PEP 8 - Style Guide for Python Code命名约定这一事实也会使事情变得“繁忙”,因为它会使语法高亮显示SO适用于所显示的代码。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
public struct TData
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
public protocol string;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =1)]
public messageType string;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
public measurement
...
public int getProtocol(){return Convert.ToInt32(protocol);}
...
}
public string get(){
var strSource="03EMSTR...";
IntPtr pbuf = Marshal.StringToBSTR(buf);
TData data= (TData)Marshal.PtrToStructure(pbuf,typeof(TData))
}
答案 1 :(得分:0)
您可以使用默认参数和命名参数来解决问题。
但如果您需要具有这么多参数的函数,我会说您可能会使您的程序更加面向对象。
创建一个类,其实例包含__call__
运算符(或只是一个方法),其中包含您最常使用的参数。
并为其提供其他方法来控制不经常更改的设置。
答案 2 :(得分:0)
使用默认参数(正如评论中指出的那样,即def func(a, optional=None, optional2=None ...):
,或者您也可以这样做:
def Instrument_Type_Calcs_C(InstType_C, **kwargs):
# You can also simply added a proper list of strings, I was merely to lazy to write on up
allowed_kwargs = ('raw_data_LP, maxcounts_C, Measurement_Min,
Measurement_Max, Measurement_Type, SG, Tank_Shape, area,
dish, diameter, length, Strapping_Table, Poly_Data,
Tank_Number, LevelOffset').strip(' ').split(',')
wrong_kwargs = [k for in kwargs if k not in allowed_kwargs]
if wrong_kwargs:
raise ValueError("Invalid Kwarg passed! %s" wrong_kwargs)
# rest of your code
...
kwargs
表示打包到dict中的所有命名参数,因此您可以在函数中访问它,就像访问字典一样。
但正如已经指出的那样,您应该考虑oop
代码。上述解决方案只是简化了函数头,而不是函数的可读性,也没有达到更好的简单性。
顺便说一句,您还可以在函数中使用已加星标的表达式(**
和*
) - 它们实际上是解包列表(*
)或字典(**
)。这在例如列表推导或解包到其他变量时非常有用:
l = ['hello', 1, 2]
s, *nums = *l
s # 'hello'
nums # [1, 2]
答案 3 :(得分:-1)
您可以使用字典“参数”之类的参数,其中包含您需要的所有参数。像这样:
def FoobarFunction(parameters):
if parameters["KnownParameter"] == ... :
# Do Something
...