2009-12-19 2 views
1

이 코드 블록은 반복되는 데이터 집합 숫자가 인 파일을 반복하고 각 집합에 대해 5 가지 정보를 추출합니다.이 파이썬 코드 블록을보다 효율적으로 리팩터링하는 방법

하지만 현재 인수 분해가 각 줄마다 각 키를 통해 을 반복하고 있기 때문에 가능한만큼 효율적이지 않다는 것을 알고 있습니다.

일부 파이썬 전문가가 더 효율적으로이 작업을 수행 할 수 있는지 궁금해 할 때 궁금합니다.

def parse_params(num_of_params,lines): 

    for line in lines: 
    for p in range(1,num_of_params + 1,1): 
     nam = "model.paramName "+str(p)+" " 
     par = "model.paramValue "+str(p)+" " 
     opt = "model.optimizeParam "+str(p)+" " 
     low = "model.paramLowerBound "+str(p)+" " 
     upp = "model.paramUpperBound "+str(p)+" " 
     keys = [nam,par,opt,low,upp] 
     for key in keys: 
     if key in line: 
      a,val = line.split(key) 
      if key == nam: names.append(val.rstrip()) 
      if key == par: params.append(val.rstrip()) 
      if key == opt: optimize.append(val.rstrip()) 
      if key == upp: upper.append(val.rstrip()) 
      if key == low: lower.append(val.rstrip()) 

print "Names = ",names 
print "Params = ",params 
print "Optimize = ",optimize 
print "Upper = ",upper 
print "Lower = ",lower 
+2

입력 데이터를 제공해 주시겠습니까? – adamse

+1

더 효율적입니까? 당신은 평범하고 질서 정연 한 일기로 그것을 작성해야합니다. 복합 데이터를 단일 문자열에 저장하지 않고 작동하는 간단한 코드를 사용해보십시오. 종종 단순히 코드를 더 잘 표현하면 필요한 "최적화"가 모두 제공됩니다. – u0b34a0f6ae

답변

1

중복이 많이있어, 혹시 추가하면 다른 key 또는 param, 당신은 오류에 대해 당신이 잘 익은 잎, 이는 많은 장소에서 추가해야 할 것입니다. 당신이하고 싶은 일은 반복되는 일들을 모두 처리하고 dict과 같은 일종의 데이터 모델을 사용하는 것입니다.

몇 가지 훌륭한 예를 제공 했으므로 여기에 대한 답을 남겨 두었습니다.

1

예상되는 형식을 완전히 쉽게 볼 수있는 것은 아닙니다.

lines = [ 
    "model.paramName 1 foo", 
    "model.paramValue 2 bar", 
    "model.optimizeParam 3 bat", 
    "model.paramLowerBound 4 zip", 
    "model.paramUpperBound 5 ech", 
    "model.paramName 1 foo2", 
    "model.paramValue 2 bar2", 
    "model.optimizeParam 3 bat2", 
    "model.paramLowerBound 4 zip2", 
    "model.paramUpperBound 5 ech2", 
] 

내가 각 라인에 하나 개 이상의 값이있는 경우 위의 코드가 작동 표시되지 않습니다 : 내가 볼 수있는 바로는, 형식은 같다. 그 말은 내가 뭔가를 놓치지 않으면 그 숫자가 그다지 중요하지 않다는 것을 의미합니다. 이 경우이 아주 쉽게 작동합니다

import re 

def parse_params(num_of_params,lines): 
    key_to_collection = { 
     "model.paramName":names, 
     "model.paramValue":params, 
     "model.optimizeParam":optimize, 
     "model.paramLowerBound":upper, 
     "model.paramUpperBound":lower, 
    } 

    reg = re.compile(r'(.+?) (\d) (.+)') 

    for line in lines: 
     m = reg.match(line) 
     key, digit, value = m.group(1, 2, 3) 
     key_to_collection[key].append(value) 
1

그것은 당신의 코드에서 완전히 분명 아니지만, 그것은 하나의 가장 "공격"할 수 있습니다 각 라인처럼 보이는; 즉 실제로 사건 있다면, 뭔가 같은 :

import re 

def parse_params(num_of_params, lines): 
    sn = 'Names Params Optimize Upper Lower'.split() 
    ks = '''paramName paramValue optimizeParam 
      paramLowerBound paramUpperBound'''.split() 
    vals = dict((k, []) for k in ks) 
    are = re.compile(r'model\.(%s) (\d+) (.*)' % '|'.join(ks)) 
    for line in lines: 
    mo = are.search(line) 
    if not mo: continue 
    p = int(mo.group(2)) 
    if p < 1 or p > num_of_params: continue 
    vals[mo.group(1)].append(mo.group(3).rstrip()) 
    for k, s in zip(ks, sn): 
    print '%-8s =' % s, 
    print vals[k] 

는 작동 할 수 있습니다 - 다음과 같이 내가 약간의 코드로 행사 :

if __name__ == '__main__': 
    lines = '''model.paramUpperBound 1 ZAP 
    model.paramLowerBound 1 zap 
    model.paramUpperBound 5 nope'''.splitlines() 
    parse_params(2, lines) 

을 그리고

Names = [] 
Params = [] 
Optimize = [] 
Upper = ['zap'] 
Lower = ['ZAP'] 

을 방출하는 I 생각하는 것이 무엇인지 생각해보십시오 (세부 사항이 다를 경우 정확한 내용을 표시하고 수정 가능 여부를 알려주십시오).

두 가지 주요 아이디어는 다음과 같습니다. if 대신에 dict을 사용하십시오. re을 사용하여 관심있는 비트 (model. 다음의 키워드, 그 이후의 정수 및 나머지 줄)를 포착하기 위해 "다음 가능성 중 하나"를 괄호로 묶은 그룹과 일치 시키십시오. if x in y 수표 및 문자열 조작이 많습니다.

2

이 질문에 답변하지 못했지만 (다른 답변은 그걸 얻고 있습니다.) 내가하는 일과 비슷한 일을하는 데 많은 도움이 된 것이 List Comprehensions입니다. 그들은 당신이 목록을 간결하게 작성할 수 있도록하고 (나는 생각하기에) 읽기 쉬운 방법이다.

예를 들어, 아래 코드는 얻으려는 값으로 2 차원 배열을 만듭니다. some_funct 여기에 약간의 정규식이 될 것입니다. 내가하고 있다면 키의 마지막 공간의 인덱스를 매개 변수로 사용하고 줄에 넣으려고하는 값을 수집합니다 (이 값은 현재 바라보고있는 키까지)를 찾아서 seen_keys 2D 배열의 올바른 색인에 추가합니다.

Wordy, 네,하지만 목록 이해력을 얻었고이를 수행 할 수있는 정규 표현식을 만들 수 있다면 멋지고 간결한 솔루션을 얻을 수 있습니다. 영업에 주어진

keys = ["model.paramName ","model.paramValue ","model.optimizeParam ""model.paramLowerBound ","model.paramUpperBound "] 
for line in lines: 
    seen_keys = [[],[],[],[],[]] 
    [seen_keys[keys.index(k)].some_funct(line.index(k) for k in keys if k in line] 
+2

목록 내장은 한 줄에 들어 맞는 간단한 표현식입니다. 이 경우 그렇지 않으므로 명시 적 루프를 사용해야합니다. * 가독성 계산 * – jfs

+0

분명히 사실입니다. 특히 의미 론적 표현 목록 이해력을 사용하면 복잡한 사용을 보완 할 수 있기 때문에이 추상화 계층에서 유혹을 느낄 수 있습니다. 그러나 대부분 개인적인 취향입니다. 그래도 가독성 측면에서 잘못하는 것이 좋습니다. 여기에는 동의하지 않습니다. – Isaac

1

코드는 즉석에서 구성되고, 각각의 값의 예상 집합에 대해 일치하려고 줄에 여러 테스트를 수행합니다. paramValue1, paramValue2 등을 각 줄마다 작성하는 대신 정규식을 사용하여 저렴하고 (그리고보다 견고한 방식으로) 일치를 시도 할 수 있습니다.

내 코드는 이미 게시 된 아이디어를 바탕으로 작성되었습니다. 이렇게하면 key_to_collection 사전에 새 키워드를 추가 할 수 있으며 다른 것을 변경할 필요가 없습니다.

import re 

def parse_params(num_of_params, lines): 

    pattern = re.compile(r""" 
     model\. 
     (.+) # keyword 
     (\d+) # index to keyword 
     [ ]+ # whitespace 
     (.+) # value 
     """, re.VERBOSE) 

    key_to_collection = { 
     "paramName": names, 
     "paramValue": params, 
     "optimizeParam": optimize, 
     "paramLowerBound": upper, 
     "paramUpperBound": lower, 
    } 

    for line in lines: 
     match = pattern.match(line) 
     if not match: 
      print "Invalid line: " + line 
     elif match[1] not in key_to_collection: 
      print "Invalid key: " + line 
     # Not sure if you really care about enforcing this 
     elif match[2] > num_of_params: 
      print "Invalid param: " + line 
     else: 
      key_to_collection[match[1]].append(match[3]) 

전체 공개 : 나는 컴파일 /이 테스트하지 있습니다.

1

parse_params가 병목인지 확인 하시겠습니까? 앱을 프로파일 링 했습니까?

import re 
from collections import defaultdict 

names = ("paramName paramValue optimizeParam " 
     "paramLowerBound paramUpperBound".split()) 
stmt_regex = re.compile(r'model\.(%s)\s+(\d+)\s+(.*)' % '|'.join(names)) 

def parse_params(num_of_params, lines): 
    stmts = defaultdict(list) 
    for m in (stmt_regex.match(s) for s in lines): 
     if m and 1 <= int(m.group(2)) <= num_of_params: 
      stmts[m.group(1)].append(m.group(3).rstrip()) 

    for k, v in stmts.iteritems(): 
     print "%s = %s" % (k, ' '.join(v)) 
0

확실히 더 효율적으로 만들 수 있습니다. 그러나 솔직히 말해서이 기능이 초당 수백 번 호출되거나 수천 줄에 작동하지 않는 한 필요하지 않습니까?

나는 무엇이 일어나고 있는지 분명히하는 것에 더 관심이 있습니다 ... 현재, 나는 그면에서 분명하지 않습니다.

model.paramName model.paramValue 1 A 1 B C model.paramLowerBound model.optimizeParam 1 1 1 model.paramUpperBound D E model.paramName 2

그냥 째려 입력은 다음과 같이 보인다 F model.paramValue 2 G model.optimizeParam 2 H model.paramLowerBound이 나는

J 2 model.paramUpperBound 그리고 원하는 출력은 같은 것 같다 : 내 입력하기 때문에,

Names  = AF 
Params = BG 
etc...

지금 확실히 당신과 일치하지 않습니다, 출력은 너무 가능성이 있지만, 내가 생각하는 것 같아요.

몇 가지 사항이 있습니다. 먼저 함수에 전달되는 매개 변수의 수는 중요합니까? 예를 들어, 입력에 두 개의 매개 변수 세트가있는 경우 두 가지 모두를 읽으려고합니까? 아니면 함수가 하나만 읽도록 허용해야합니까? 예를 들어, 코드를 사용하면 parse_params(1,1)을 호출하고 동일한 입력에서 1로 끝나는 매개 변수 만 읽을 수 있습니다. 이것이 실제로 요구 사항이 아니라면 코드의 큰 덩어리를 건너 뛸 수 있습니다.

둘째, 주어진 매개 변수 만 읽는 것이 중요합니까? 예를 들어, 'paramFoo'라는 매개 변수가 있다면 읽으면 좋지 않습니까? 또한 이름에 관계없이 모든 매개 변수를 가져 와서 값을 추출하여 프로 시저를 단순화 할 수 있습니다.

def parse_params(input): 
    parameter_list = {} 
    param = re.compile(r"model\.([^ ]+) [0-9]+ ([^ ]+)") 
    each_parameter = param.finditer(input) 
    for match in each_parameter: 
    key = match[0] 
    value = match[1] 
    if not key in paramter_list: 
     parameter_list[key] = [] 

    parameter_list[key].append(value) 

    return parameter_list

출력은 이때이 같을 것이다 :

{ 'paramName에': A, F, 'paramValue': [B, G, 'optimizeParam': C, H] 등}}

Notes : 저는 파이썬을 잘 모릅니다. 저는 루비 녀석입니다. 그래서 제 문법이 꺼져있을 수 있습니다. 사과.

관련 문제