2016-12-28 79 views
12

我有两个需要解析的类似代码,我不确定用什么方法来完成这个。如何编写两个函数,其外部函数为内部函数提供参数

假设我有两个类似的“代码”

secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing' 
secret_code_2 = 'qwersdfg-qw|er$$otherthing' 

两个码与$$otherthing结束,并且含有许多由-

分离。在第一值的我想用functools.wrap分离一些常见的从逻辑特定的每种类型的代码,如下所示:

from functools import wraps 

def parse_secret(f): 
    @wraps(f) 
    def wrapper(code, *args): 
    _code = code.split('$$')[0] 
    return f(code, *_code.split('-')) 
    return wrapper 

@parse_secret 
def parse_code_1b(code, a, b, c): 
    a = a.split('|')[0] 
    return (a,b,c) 

@parse_secret 
def parse_code_2b(code, a, b): 
    b = b.split('|')[1] 
    return (a,b) 

但是做这种方式使得它种混淆什么参数,你其实应该传递给parse_code_*功能即

parse_code_1b(secret_code_1) 
parse_code_2b(secret_code_2) 

所以要保持函数的形式参数更容易推理,我改变了逻辑是这样的:

def _parse_secret(parse_func, code): 
    _code = code.split('$$')[0] 
    return parse_func(code, *_code.split('-')) 

def _parse_code_1(code, a, b, c): 
    """ 
    a, b, and c are descriptive parameters that explain 
    the different components in the secret code 

    returns a tuple of the decoded parts 
    """ 
    a = a.split('|')[0] 
    return (a,b,c) 

def _parse_code_2(code, a, b): 
    """ 
    a and b are descriptive parameters that explain 
    the different components in the secret code 

    returns a tuple of the decoded parts 
    """ 
    b = b.split('|')[1] 
    return (a,b) 

def parse_code_1(code): 
    return _parse_secret(_parse_code_1, code) 

def parse_code_2(code): 
    return _parse_secret(_parse_code_2, code) 

现在,它更容易推理,你传递给函数的内容:

parse_code_1(secret_code_1) 
parse_code_2(secret_code_2) 

但是这个代码是显著更冗长。

有没有更好的方式来做到这一点?在类中使用面向对象的方法会更有意义吗?

repl.it example

回答

2

repl.it example

功能的方法是更简洁,更有意义。

我们可以从表达概念pure functions开始,这是最简单的组成形式。

地带$$otherthing和分裂值:

parse_secret = lambda code: code.split('$$')[0].split('-') 

径内的值之一:

take = lambda value, index: value.split('|')[index] 

替换其内的值中的一个值:

parse_code = lambda values, p, q: \ 
    [take(v, q) if p == i else v for (i, v) in enumerate(values)] 

这些2种类型码具有3间的区别:

0123值的
  • 位置来解析“内部”值“内部”值
  • 位置采取

而且我们可以通过描述这些不同组合解析功能。分割值保持压缩状态,以便更容易组成。

compose = lambda length, p, q: \ 
    lambda code: parse_code(parse_secret(code)[:length], p, q) 

parse_code_1 = compose(3, 0, 0) 
parse_code_2 = compose(2, 1, 1) 

而且使用的功能组成:

secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing' 
secret_code_2 = 'qwersdfg-qw|er$$otherthing' 
results = [parse_code_1(secret_code_1), parse_code_2(secret_code_2)] 
print(results) 
+2

使用命名的lambda功能的[通过PEP8劝阻](http://www.python.org/dev/peps/pep-0008/#programming-recommendations) –

0

我认为你需要提供你想实现什么,什么明确的约束更多的信息。例如,$$可以发生多少次?总会有一个| dividor吗?那种事。

要广泛回答你的问题,一个优雅的pythonic方法是使用python的拆箱功能,并结合split。例如

secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing' 

first_$$_part, last_$$_part = secret_code_1.split('$$') 

通过使用该技术,除了简单if块,你应该能够写一个优雅的解析器。

1

我相信这样的事情会工作:

secret_codes = ['asdf|qwer-sdfg-wert$$otherthing', 'qwersdfg-qw|er$$otherthing'] 


def parse_code(code): 
    _code = code.split('$$') 
    if '-' in _code[0]: 
     return _parse_secrets(_code[1], *_code[0].split('-')) 
    return _parse_secrets(_code[0], *_code[1].split('-')) 


def _parse_secrets(code, a, b, c=None): 
    """ 
    a, b, and c are descriptive parameters that explain 
    the different components in the secret code 

    returns a tuple of the decoded parts 
    """ 
    if c is not None: 
     return a.split('|')[0], b, c 
    return a, b.split('|')[1] 


for secret_code in secret_codes: 
    print(parse_code(secret_code)) 

输出:

('asdf', 'sdfg', 'wert') 
('qwersdfg', 'er') 

我不知道你的秘密数据的结构,但如果你使用的元素与位置的索引有|的数据在它和有秘密数据适当数量的你也可以做这样的事情,并有秘密的无限(以及几乎)量可能:

def _parse_secrets(code, *data): 
    """ 
    data is descriptive parameters that explain 
    the different components in the secret code 

    returns a tuple of the decoded parts 
    """ 
    i = 0 
    decoded_secrets = [] 
    for secret in data: 
     if '|' in secret: 
      decoded_secrets.append(secret.split('|')[i]) 
     else: 
      decoded_secrets.append(secret) 
     i += 1 
    return tuple(decoded_secrets) 
1

我真的不知道究竟你的意思。但是我想出了你可能想要的东西。

怎么样用一个简单的功能是这样的:

def split_secret_code(code): 
    return [code] + code[:code.find("$$")].split("-") 

而不仅仅是使用:

parse_code_1(*split_secret_code(secret_code_1)) 
0

如果我理解正确的话,你希望能够来定义你的作用就好像分析的参数被传递,但是想要将未解析的代码传递给函数。

您可以非常类似于您提供的第一个解决方案。

from functools import wraps 

def parse_secret(f): 
    @wraps(f) 
    def wrapper(code): 
    args = code.split('$$')[0].split('-') 
    return f(*args) 
    return wrapper 

@parse_secret 
def parse_code_1(a, b, c): 
    a = a.split('|')[0] 
    return (a,b,c) 

@parse_secret 
def parse_code_2(a, b): 
    b = b.split('|')[1] 
    return (a,b) 

对于本例中提到的暗号,

secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing' 

print (parse_code_1(secret_code_1)) 
>> ('asdf', 'sdfg', 'wert') 

secret_code_2 = 'qwersdfg-qw|er$$otherthing' 
print (parse_code_2(secret_code_2)) 
>> ('qwersdfg', 'er') 
0

我没有理解你的问题,既不是你的代码,但也许一个简单的方法来做到这一点是通过正则表达式的东西吗?

import re 

secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing' 
secret_code_2 = 'qwersdfg-qw|er$$otherthing' 

def parse_code(code): 
    regex = re.search('([\w-]+)\|([\w-]+)\$\$([\w]+)', code) # regular expression 
    return regex.group(3), regex.group(1).split("-"), regex.group(2).split("-") 

otherthing, first_group, second_group = parse_code(secret_code_2) 

print(otherthing) # otherthing, string 
print(first_group) # first group, list 
print(second_group) # second group, list 

输出:

otherthing 
['qwersdfg', 'qw'] 
['er'] 
1

你结婚了字符串解析?如果你使用值传递变量而不需要变量名,你可以将它们“包装”为整数。

如果你正在使用密码学,你可以制定一个长十六进制字符数,然后以“停止”字节的形式将其作为int传递(例如0000,因为“0”实际上是48尝试:chr(48)),如果你已经结婚字符串我会建议一个较低的字符字节标识符为例(1 - >又名:chr(1)),所以你可以扫描整数和位移8,以获得8位掩码字节(这看起来像(secret_code>>8)&0xf

散列工作在类似的方式自一个变量与somenamesomeValue中somename一些值可以解析为整数,然后加入停止模块,然后在需要时进行检索。

让我给你一个例子散列

# lets say 
a = 1 
# of sort hashing would be 
hash = ord('a')+(0b00<<8)+(1<<16) 
#where a hashed would be 65633 in integer value on 64 bit computer 
# and then you just need to find a 0b00 aka separator 

,如果你希望只使用变量(名称并不重要),那么你需要哈希只有变量的值,从而分析得到的值的大小是很多小(没有名字的一部分,且无需分离器(0B00),你可以使用分离器巧妙地划分必要的数据一个倍(0B00)twofolds(0B00,0B00 < < 8)等

a = 1 
hash = a<<8 #if you want to shift it 1 byte 

但是,如果你想隐藏它,你需要密码学的例子,你可以做上面的方法,然后争夺,转移(a-> b)或稍后将其转换为另一种类型。你只需要弄清楚你正在做的操作的顺序。由于a-STOP-b-PASS-c不等于a-PASS-b-STOP-c。

您可以在这里找到位运算符binary operators

但不得不记住,65号,65是一个字符,以及在哪里发送这些字节只在乎,如果他们被送到显卡,他们是像素,如果他们被发送到audiocard他们是声音,如果他们被送到数学处理他们是数字,并作为程序员,这是我们的操场。

但是,如果这不是回答你的问题,你可以随时使用地图。

def mapProcces(proccesList,listToMap): 

    currentProcces = proccesList.pop(0) 
    listToMap = map(currentProcces, listToMap) 

    if proccesList != []: 
     return mapProcces(proccesList, listToMap) 
    else: 
     return list(listToMap) 

,那么你可以映射它:

mapProcces([str.lower,str.upper,str.title],"stackowerflow") 

,或者你可以简单地使用空间,然后分割空间,代替的每一正式分离。

secret_code_1 = 'asdf|qwer-sdfg-wert$$otherthing' 
separ = "|,-,$".split(",") 
secret_code_1 = [x if x not in separ else " " for x in secret_code_1]# replaces separators with empty chars 
secret_code_1 = "".join(secret_code_1) #coverts list to a string 
secret_code_1 = secret_code_1.split(" ") #it splited them to list 
secret_code_1 = filter(None,secret_code_1) # filter empty chars '' 
first,second,third,fourth,other = secret_code_1 

在那里,你有它,你的secret_code_1被分割并分配给明确数量的变量。当然用“”作为声明,你可以使用任何你想要的,你可以用“someseparator”替换每个分隔符,然后用“someseparator”分割。您还可以使用str.replace函数使其更清晰。

我希望这有助于

1

我不知道你正在使用什么限制,但它看起来像:

  1. 有不同类型的代码有不同的规则
  2. 的破折号分开ARGS的数目可以变化
  3. 在arg具有管可以变化

直截了当的例子

这不是很难解决,你不需要花哨的包装,所以我会放弃它们,因为它增加了阅读的复杂性。

def pre_parse(code): 
    dash_code, otherthing = code.split('$$') 
    return dash_code.split('-') 

def parse_type_1(code): 
    dash_args = pre_parse(code) 
    dash_args[0], toss = dash_args[0].split('|') 
    return dash_args 

def parse_type_2(code): 
    dash_args = pre_parse(code) 
    toss, dash_args[1] = dash_args[1].split('|') 
    return dash_args 

# Example call 
parse_type_1(secret_code_1) 

试图回答的问题作为陈述

您可以使用Python的本土装饰图案*相结合,这卷以这种方式提供参数/解开的位置参数到一个元组,所以你不” t需要确切知道有多少。

def dash_args(code): 
    dash_code, otherthing = code.split('$$') 
    return dash_code.split('-') 

def pre_parse(f): 
    def wrapper(code): 
     # HERE is where the outer function, the wrapper, 
     # supplies arguments to the inner function. 
     return f(code, *dash_args(code)) 
    return wrapper 

@pre_parse 
def parse_type_1(code, *args): 
    new_args = list(args) 
    new_args[0], toss = args[0].split('|') 
    return new_args 

@pre_parse 
def parse_type_2(code, *args): 
    new_args = list(args) 
    toss, new_args[1] = args[1].split('|') 
    return new_args 

# Example call: 
parse_type_1(secret_code_1) 

更多可扩展的实例

如果由于某种原因,你需要支持对这种分析的很多变化,你可以使用一个简单的面向对象的设置,像

class BaseParser(object): 
    def get_dash_args(self, code): 
     dash_code, otherthing = code.split('$$') 
     return dash_code.split('-') 

class PipeParser(BaseParser): 
    def __init__(self, arg_index, split_index): 
     self.arg_index = arg_index 
     self.split_index = split_index 

    def parse(self, code): 
     args = self.get_dash_args(code) 
     pipe_arg = args[self.arg_index] 
     args[self.arg_index] = pipe_arg.split('|')[self.split_index] 
     return args 

# Example call 
pipe_parser_1 = PipeParser(0, 0) 
pipe_parser_1.parse(secret_code_1) 
pipe_parser_2 = PipeParser(1, 1) 
pipe_parser_2.parse(secret_code_2) 
1

我的建议尝试以下:

  • 是非-verbose足够
  • 到以明确的方式分离和共同特定逻辑
  • 为足够的可扩展

基本上,它分隔常见和特定的逻辑到不同的函数(你可以做使用OOP相同)。问题是它根据每个代码的内容使用包含逻辑的映射器变量来选择特定的解析器。这里有云:

def parse_common(code): 
     """ 
     Provides common parsing logic. 
     """ 
     encoded_components = code.split('$$')[0].split('-') 
     return encoded_components 

    def parse_code_1(code, components): 
     """ 
     Specific parsing for type-1 codes. 
     """ 
     components[0] = components[0].split('|')[0] # decoding some type-1 component 
     return tuple([c for c in components]) 

    def parse_code_2(code, components): 
     """ 
     Specific parsing for type-2 codes. 
     """ 
     components[1] = components[1].split('|')[1] # decoding some type-2 component 
     return tuple([c for c in components]) 

    def parse_code_3(code, components): 
     """ 
     Specific parsing for type-3 codes. 
     """ 
     components[2] = components[2].split('||')[0] # decoding some type-3 component 
     return tuple([c for c in components]) 

    # ... and so on, if more codes need to be added ... 

    # Maps specific parser, according to the number of components 
    CODE_PARSER_SELECTOR = [ 
     (3, parse_code_1), 
     (2, parse_code_2), 
     (4, parse_code_3) 
    ] 

    def parse_code(code): 
     # executes common parsing 
     components = parse_common(code) 

     # selects specific parser 
     parser_info = [s for s in CODE_PARSER_SELECTOR if len(components) == s[0]] 

     if parser_info is not None and len(parser_info) > 0: 
      parse_func = parser_info[0][1] 
      return parse_func(code, components) 
     else: 
      raise RuntimeError('No parser found for code: %s' % code) 

    secret_codes = [ 
     'asdf|qwer-sdfg-wert$$otherthing',    # type 1 
     'qwersdfg-qw|er$$otherthing',     # type 2 
     'qwersdfg-hjkl-yui||poiuy-rtyu$$otherthing'  # type 3 
     ] 

    print [parse_code(c) for c in secret_codes] 
+0

我爱解析器地图的想法! – Tom