Question: How to compose two functions whose outer function supplies arguments to the inner function

Question

How to compose two functions whose outer function supplies arguments to the inner function

Answers 1
Added at 2016-12-28 21:12
Tags
Question

I have two similar codes that need to be parsed and I'm not sure of the most pythonic way to accomplish this.

Suppose I have two similar "codes"

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

both codes end with $$otherthing and contain a number of values separated by -

At first I thought of using functools.wrap to separate some of the common logic from the logic specific to each type of code, something like this:

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)

However doing it this way makes it kind of confusing what parameters you should actually pass to the parse_code_* functions i.e.

parse_code_1b(secret_code_1)
parse_code_2b(secret_code_2)

So to keep the formal parameters of the function easier to reason about I changed the logic to something like this:

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)

Now it's easier to reason about what you pass to the functions:

parse_code_1(secret_code_1)
parse_code_2(secret_code_2)

However this code is significantly more verbose.

Is there a better way to do this? Would an object-oriented approach with classes make more sense here?

repl.it example

Answers
nr: #1 dodano: 2017-01-03 23:01

I think you need to provide more information of exactly what you're trying to achieve, and what the clear constraints are. For instance, how many times can $$ occur? Will there always be a | dividor? That kind of thing.

To answer your question broadly, an elegant pythonic way to do this is to use python's unpacking feature, combined with split. for example

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

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

By using this technique, in addition to simple if blocks, you should be able to write an elegant parser.

Source Show
◀ Wstecz