This is mine solution if someone has better please comment or correct.
the idea:
The idea is that every class could have a list of aliases to specific attributes so user could (based on class name logic :> point needs x,y,z,name attributes, dog needs breed,name,age,sex attributes and so on ) based on its own internal logic to call attributes without need for knowing exactly what attribute name sed attribute have.
the logic:
If function or class has for input some keyword arguments, then I would need minimal list of common words associated with sed argument. Synonyms and idioms can be googled easily but i would advise against the big list of synonyms, keep it small 2-3 + attribute name . Then all we need is to map those aliases to the original attribute since we as codes need to know how to call attribute without calling getattr(self,someattributestring)
code:
Chronologically we must first define a function to generate aliases.
# 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) )
Now we need to map and check those arguments inside function or class so we need some argument parser.
## **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
implementation
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) )
output
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)
If implemented in classes, the process is similar in __init__
but __getitem__
, __setitem__
and __delitem__
must be coded so they could search for attribute names in aliases as well. Also attribtribute names could be generated with self.attributes = list( aliases.keys())
or something like that.Default values could be stored in classes with __kwdefaults__
or 'defaults' depending what kind of data your function is using.
this code has been tested on py2.7 and py3.5 as you can see.
further explanation if needed
You can define aliases within class global attributes or within __init__
.
Explaining further __getitem__
:
def __getitem__(self,item):
if item in self.aliases.keys():
return getattr(self,item)
if any( item in value for value in self.aliases.values() ):
item = [ key for key in self.aliases.keys() if item in self.aliases[key] ] [0]
return getattr(self,item)
if item in range( len( self.aliases.keys() ) ):
item = list( self.aliases.keys() )[item]
return getattr(self,item)
Explaining further __setitem__
:
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)