2017-01-21 5 views
1

Мне всегда казалось странным, что есть аргументы (или аргументы) ключевого слова, которые могут быть переданы функциям или __init__ методов классов. Как вы запрещаете пользователю, который не знаком с вашим кодом, совершать ошибку? Как заставить пользователя мгновенно (почти интуитивно) знакомы с вашим кодом без плохо написанной или долговечной документации или для многих проб и ошибок, позволяющих пользователю быстро и комфортно использовать ваш код или модуль?Псевдонимы аргументов аргументов в python

В python нам повезло, так как у нас есть help и dir функции, которые часто могут помочь нам лучше понять, что некоторые параметры функции. Но иногда есть плохо написанная строка __doc__, которая ничего не объясняет.

Позвольте мне дать вам несколько примеров того, что я имею в виду:

>>> help(str.lower) 
    Help on method_descriptor: 

     lower(...) 
     S.lower() -> string 

    Return a copy of the string S converted to lowercase 

. Например, у нас есть функция, которая имеет ... входные параметры. Что означает этот параметр, для полного новичка (как и я, когда я впервые погрузился в python), это сбивало с толку, и часто я просто пропустил этот раздел.

Некоторые веб-сайты, предлагающие советы или учебники, просто распечатывают справочный файл функций или реализуют только одну из многих функций функции sed.

1 functionality of example function

или непосредственно из python.org

str.lower()
возвращает копию строки со всеми обсаженных символами [4], преобразованных в нижний регистр. Для 8-битных строк этот метод зависит от языка.

Теперь для тех, кто только начал программировать и не (или не может) погрузиться в биты и байты, адреса и т. Д., Это какое-то древнее заклинание, которое может выполнять только мастер-колдун, даже не позволять мне началось с того, почему это не помогает людям, не говорящим по-английски.

Для этой конкретной функции функции я могу найти 2-3 дополнительных примера, где он может выполнять свою работу по-другому, также мне нужно было выяснить, что эта примерная функция может быть использована путем ввода строки в str.lower(here).

Большая проблема здесь (как я ее вижу, конечно) состоит в том, что str с небольшим количеством поисковых запросов может быть описательным сама по себе, и ее функциональность может быть логически заключена только через wikipedia.

Если я суммирую вопросы, прост, существует ли способ изменить ключевые слова при использовании в качестве параметров, чтобы принимать больше имен, чем мы определяем, поэтому пользователю не нужно было бы разорвать его/ее волосы на первом этапе введения учебника ?

Теперь я знаю, что некоторые из вас, ребята, скажут что-то по строкам: «Если вы не понимаете этого, не делайте этого» или «я не йо мама, чтобы научить вас чему-то» ... тому, что я должны сказать, что «разделение - это забота» и «вам иногда нужна помощь в кодировании, иначе вы не были бы на этом сайте».

+0

Извините, но это звучит как * * страшном идея для меня. Функции должны принимать четко определенные аргументы, а не список аргументов, которые «пользователь может (базовая логика имени дочернего класса)» проходить. –

+0

Я согласен с вами в отношении типа, но не с именем.Но мне интересно, как вы думаете, что получится, если имя будет известно и четко/строго определено, если пользователь не знает, какое имя вы дали локальной переменной? Я нахожусь в чате, если вы хотите продолжить эту тему по длине, мне очень любопытно узнать вашу точку зрения. – Danilo

ответ

1

Это мое решение, если кто-то лучше, пожалуйста, прокомментируйте или исправьте.

идея:
Идея заключается в том, что каждый класс может иметь список псевдонимов для конкретных атрибутов так что пользователь может (на основе имени класса логики:> потребность точки х, у, г, атрибуты имени, потребности собаки породу, имя, возраст, атрибуты пола и т. д.) на основе собственной внутренней логики для вызова атрибутов без необходимости точно знать, какое атрибут атрибута 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)