python中的关键字参数别名
我总是觉得奇怪,有一些关键字参数(或参数)可以传递给函数或类的python中的关键字参数别名,python,parameters,keyword-argument,Python,Parameters,Keyword Argument,我总是觉得奇怪,有一些关键字参数(或参数)可以传递给函数或类的\uuuu init\uuu方法。如何防止不熟悉代码的用户出错?如何让用户立即(几乎是本能地)熟悉您的代码,而不必编写糟糕或冗长的文档,也不必经历许多让用户无法快速舒适地使用您的代码或模块的尝试和错误 在python中,我们很幸运,因为我们有help和dir函数,这些函数通常可以指导我们更好地理解某些函数参数是什么。但有时会有写得不好的\uuuuuuuuuuuuuuuuuuuuuuuuuu字符串无法解释任何内容 让我举几个例子来说明我
\uuuu init\uuu
方法。如何防止不熟悉代码的用户出错?如何让用户立即(几乎是本能地)熟悉您的代码,而不必编写糟糕或冗长的文档,也不必经历许多让用户无法快速舒适地使用您的代码或模块的尝试和错误
在python中,我们很幸运,因为我们有help
和dir
函数,这些函数通常可以指导我们更好地理解某些函数参数是什么。但有时会有写得不好的\uuuuuuuuuuuuuuuuuuuuuuuuuu
字符串无法解释任何内容
让我举几个例子来说明我的意思:
>>> help(str.lower)
Help on method_descriptor:
lower(...)
S.lower() -> string
Return a copy of the string S converted to lowercase
。
例如,这里我们有一些具有输入参数的函数。这个参数代表什么,对于完全的新手(就像我第一次跳入python时一样),这让人困惑,我经常跳过这一部分
一些提供建议或教程的网站只是打印出帮助功能文件,或者只是实现sed功能的许多功能之一
或者直接从python.org下载
str.lower()返回字符串的副本,其中所有大小写字符[4]都转换为小写。 对于8位字符串,此方法依赖于区域设置 对于那些刚开始编程的人来说,这是一个只有术士大师才能使用的古老咒语,他们不(或不能)深入研究比特、字节、地址等,我甚至不想让我开始解释为什么这对不说英语的人没有帮助 对于这个特殊的示例函数,我可以找出2-3个额外的示例,在这些示例中,它可以以不同的方式完成其工作,并且我必须发现,这个示例函数可以通过将字符串输入到
str.lower(此处)
部分来使用
这里的大问题(当然,我认为)是,用谷歌搜索一下str就可以自己描述,它的功能只能通过维基百科从逻辑上得出结论
如果我总结的问题很简单,有没有一种方法可以在使用作为参数时修改关键字,以接受比我们定义的更多的名称,这样用户就不必在介绍教程的第一步就扯掉他/她的头发
现在我知道你们中的一些人会说一些类似的话:“如果你不懂,就不要做”或者“我不是你妈妈教你的东西”。。。对此,我不得不说“分享就是关心”和“你有时也需要帮助编码,否则你就不会出现在这个网站上了。”这是我的解决方案,如果有人有更好的建议,请评论或更正 想法:
其思想是,每个类都可以有一个特定属性的别名列表,这样用户就可以(基于类名逻辑:>点需要x、y、z、名称属性、狗需要品种、名称、年龄、性别属性等)基于其自身的内部逻辑调用属性,而无需确切知道sed属性的属性名 逻辑:
若函数或类输入了一些关键字参数,那个么我需要和sed参数相关联的最小常用词列表。同义词和习语可以很容易地在谷歌上搜索,但我建议不要使用大量的同义词列表,保持较小的2-3+属性名。然后,我们只需要将这些别名映射到原始属性,因为作为代码,我们需要知道如何在不调用
getattr(self,someattributestring)
代码:按时间顺序,我们必须首先定义一个函数来生成别名
# generate aliases for attributes
def generateAliases(*argListNames):
returningValues = [] # this could be omitted if user wants to make generator
la = returningValues.append # this could be omitted also
#dominated argListNames
argListNames = map( str, argListNames ) #for simplicity convert to strings
argListNames = map( str.lower , argListNames ) #for simplicity convert to lower string
argListNames = list(argListNames) # back to list
# small nameless lambda functions
getFirstChr = lambda element: element[0] # getting first character
conectedJoing= lambda connector,item,args: connecter.join([ item, args if not __isTL__(args) else connecter.join(args) ]) # generating joined string
# list of string convertors used to generate aliases
convertorList= [ lambda x: x , getFirstChr , str.title , str.upper , lambda x: getFirstChr( str.upper(x) ) ]
for item in argListNames:
## since we dont want alias to repeat itself
listNoitem = filter( lambda x: x!=item , argListNames )
listNoitem = list(listNoitem)
la(item) # if returningValues omitted use yield statement
for conversion in convertorList: ##1 keeping up with for loops
converted = conversion(item)
for connecter in "_,".split(","):
for listItem in listNoitem:
for cnvrt in convertorList: ##2 cnvrt is converted second stage : used to convert the whole list of items without current alias
cList = cnvrt(listItem)
la( conectedJoing(connecter,converted,cList) )# if returningValues omitted use yield statement
la( conectedJoing(connecter,converted,listNoitem) )# if returningValues omitted use yield statement
# if user wanted to make generator omit next lines
returningValues = [ x.replace("_","") if x.endswith("_") else x for x in returningValues ]
returningValues = sorted(set(returningValues))
return list( map(str,returningValues) )
现在我们需要映射并检查函数或类中的参数,因此我们需要一些参数解析器
## **kwargs argument parser , no error
def argumentParser(AprovedSequence,**kwargs):
# AprovedSequence is suposed to be dictionary data type with {"original argument": generateAliases(originalArgumentName,somealias,somealias,...)
"""
phrases the keyword arguments,
for example : argumentParser(AprovedSequence,someArgument=somevalue,otherArgument=othervalue ... )
then it checks if someArgument is needed by checking in AprovedSequence if name "someArgument" is found in sequence:
If "someArgument" is found in AprovedSequence it stores returns dictionary of DefaultKeys : Values
for example: DefaultKey for someArgument: somevalue
input:
argumentParser(dict: AprovedSequence, kwargs)
returns:
dictionary of found attributes and their values
!!important!! kwargs are not case sensitive in this case , so go crazy as long as you get the apropriate keyword!!
if you dont know what kind of keywords are needed for class
just type className.errorAttributeNames()
for example point.errorAttributeNames()
"""
if isinstance(AprovedSequence,dict):
di = dict.items # dictionary.values(someDict)
dk = dict.keys # dictionary.keys(someDict)
# managing the kwargs and aprooved sequence data
toLowerStr = lambda el: str(el).lower() # conversion to lower string
asingKey = lambda el: [ key for key in dk(AprovedSequence) if toLowerStr(el) in AprovedSequence[key] ][0] # asigning key
return { asingKey(k):v for k,v in di(kwargs) } # dictionary comprehension
else:
raise TypeError("argumentPhraser function accepts only dictionary for a AprovedSequence aka first item")
return None
实施
def somefunction(**kwargs):
aliases = {
"val1":generateAliases("first","1"),
"val2":generateAliases("second","2")
}
aproved = argumentParser(aliases,**kwargs)
if "val1" in aproved.keys(): val1 = aproved["val1"]
else: val1 = 0 # seting default value for val1
if "val2" in aproved.keys(): val2 = aproved["val2"]
else: val2 = 1 # seting default value for val2
#do something or your code here
return val1,val2
# for testing purposes
for x in [ {"first":1} , {"second":2,"first":3} , {"f1":4,"s2":5} , {"f_1":6,"2_s":7} ]:
# displaying imputed variables
form = ["passed "]
form += [ "{} as {} ".format(key,value) for key,value in x.items() ]
# implementing somefunciton
print( "".join(form), somefunction(**x) )
输出
python27 -m kwtest
Process started >>>
passed first as 1 (1, 1)
passed second as 2 first as 3 (3, 2)
passed f1 as 4 s2 as 5 (4, 5)
passed 2_s as 7 f_1 as 6 (6, 7)
<<< Process finished. (Exit code 0)
python35 -m kwtest
Process started >>>
passed first as 1 (1, 1)
passed first as 3 second as 2 (3, 2)
passed f1 as 4 s2 as 5 (4, 5)
passed f_1 as 6 2_s as 7 (6, 7)
<<< Process finished. (Exit code 0)
进一步解释
def __setitem__(self,item,value):
item = self.__getitem__(self,item)
#? must have `__dict__` method or class needs to be instanced from object like class someclass(object)
item = [ key for key in vars(self).items() if self[key] == item] [0]
if item != None:
setattr(self,item,value)
我把这个装饰师改成了alias kwargs。很有魅力
def alias\u param(param\u name:str,param\u alias:str)->可调用:
"""
用于在函数中为参数添加别名的装饰器
Args:
param_name:别名函数中参数的名称
参数别名:可用于此参数的别名
返回:
"""
def装饰器(函数:可调用):
@functools.wrapps(func)
def包装(*args,**kwargs):
alias_param_value=kwargs.get(param_alias)
如果别名参数值:
kwargs[参数名称]=别名参数值
del kwargs[参数别名]
结果=函数(*args,**kwargs)
返回结果
返回包装器
然后可以像这样使用它
@alias_param(“param_1”,alias='p1')
def功能(参数1=无):
返回参数1
函数(p1='value')
类似于
def __setitem__(self,item,value):
item = self.__getitem__(self,item)
#? must have `__dict__` method or class needs to be instanced from object like class someclass(object)
item = [ key for key in vars(self).items() if self[key] == item] [0]
if item != None:
setattr(self,item,value)