Это мое решение, если кто-то лучше, пожалуйста, прокомментируйте или исправьте.
идея:
Идея заключается в том, что каждый класс может иметь список псевдонимов для конкретных атрибутов так что пользователь может (на основе имени класса логики:> потребность точки х, у, г, атрибуты имени, потребности собаки породу, имя, возраст, атрибуты пола и т. д.) на основе собственной внутренней логики для вызова атрибутов без необходимости точно знать, какое атрибут атрибута name имеет атрибут.
логика:
Если функция или класс имеет для ввода некоторые именованные аргументы, то я должен был бы минимальный список общих слов, связанных с SED аргументом. Синонимы и идиомы можно легко искать в googled, но я бы посоветовал против большого списка синонимов, сохранил это маленькое 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)
Если реализованы в классах, процесс похож на __init__
но __getitem__
, __setitem__
и __delitem__
должны быть закодированы, чтобы они могли высушивать ch для имен атрибутов в псевдонимах. Также имена атрибутов могут быть сгенерированы с помощью self.attributes = list(aliases.keys())
или что-то в этом роде. Значения значений могут храниться в классах с __kwdefaults__
или 'по умолчанию' в зависимости от того, какие данные использует ваша функция.
этот код был протестирован на py2.7 и py3.5, как вы можете видеть.
дальнейшее объяснение в случае необходимости
Вы можете определить псевдонимы в пределах глобальных атрибутов класса или внутри __init__
.
Объясняя далее __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)
Объясняя дальнейшее __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)
Извините, но это звучит как * * страшном идея для меня. Функции должны принимать четко определенные аргументы, а не список аргументов, которые «пользователь может (базовая логика имени дочернего класса)» проходить. –
Я согласен с вами в отношении типа, но не с именем.Но мне интересно, как вы думаете, что получится, если имя будет известно и четко/строго определено, если пользователь не знает, какое имя вы дали локальной переменной? Я нахожусь в чате, если вы хотите продолжить эту тему по длине, мне очень любопытно узнать вашу точку зрения. – Danilo