1

私の目標は、CSV ソース リストの修飾子のスタックに基づいてフレームワークを最適化することです。各修飾子は、ヘッダー リストを使用して名前付きベースで機能します。

CSV の例 (ヘッダーを含む):

date;place
13/02/2013;New York
15/04/2012;Buenos Aires
29/10/2010;Singapour

毎回データを再編成せずに csv モジュールによって生成されたリストを使用できるようにするために、namedtuple に基づいていくつかのコードを作成しました。以下の生成コード:

class MyNamedList(object):
        __slots__ = ("__values")
        _fields = ['date', 'ignore', 'place']

        def __init__(self, values):
          self.__values = values
          if len(self.__values) <= 151:
            for i in range(len(self.__values), 151):
              self.__values += [None,]

        @property
        def date(self):
          return self.__values[0]
        @date.setter
        def date(self, val):
          self.__values[0] = val

        @property
        def ignore(self):
          return self.__values[150]
        @ignore.setter
        def ignore(self, val):
          self.__values[150] = val

        @property
        def place(self):
          return self.__values[1]
        @b.setter
        def place(self, val):
          self.__values[1] = val

このクラスを使用したパフォーマンスには非常に失望しています。70000行のcsvファイルの各行に対して単純な修飾子関数(「無視」をTrueに100回変更します。はい、それが役に立たないことを知っています)を呼び出すと、9秒かかります(元のpythonを使用したpypy.5.5を使用) foo という名前のリストには 1.1 秒かかります (pypy と元の python と同じ)。

両方のアプローチ間で同等のパフォーマンスを得るためにできることはありますか? 私にとっては、record.ignore = True直接インライン化 (またはそのように) することができ、したがってrecord[150] = True. これを実現するために私が見ていないブロックポイントはありますか?

私が変更しているレコードは、実際には (今のところ) CSV ファイルの各行に対して作成されていないことに注意してください。つまり、リストへのアイテムの追加は、反復の前に 1 回だけ行われます。

更新:サンプルコード

--> 名前付きリストの使用

import namedlist

MyNamedList=namedlist.namedlist("MyNamedList", {"a":1, "b":2, "ignore":150})
test = MyNamedList([0,1])

def foo(a):
  test.ignore = True # x100 times

import csv
stream = csv.reader(open("66666.csv", "rb"))
for i in stream:
  foo(i)

--> 名前付きリストを使用しない

import namedlist
import csv

MyNamedList=namedlist.namedlist("MyNamedList", {"a":1, "b":2, "ignore":150})
test = MyNamedList([0,1])

sample_data = []
for i in range(len(sample_data), 151):
  sample_data += [None,]

def foo(a):
  sample_data[150] = True # x100 times

stream = csv.reader(open("66666.csv", "rb"))
for i in stream:
  foo(i)

更新 #2 : namedlist.py のコード (namedtuple.py に大きく基づいています)

# Retrieved from http://code.activestate.com/recipes/500261/
# Licensed under the PSF license

from keyword import iskeyword as _iskeyword
import sys as _sys

def namedlist(typename, field_indices, verbose=False, rename=False):

    # Parse and validate the field names.  Validation serves two purposes,
    # generating informative error messages and preventing template injection attacks.
    field_names = field_indices.keys()
    for name in [typename,] + field_names:
        if not min(c.isalnum() or c=='_' for c in name):
            raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError('Type names and field names cannot start with a number: %r' % name)
    seen_names = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: %r' % name)
        if name in seen_names:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen_names.add(name)

    # Create and fill-in the class template
    numfields = len(field_names)
    argtxt = repr(field_names).replace("'", "")[1:-1]   # tuple repr without parens or quotes
    reprtxt = ', '.join('%s=%%r' % name for name in field_names)
    max_index=-1
    for name in field_names:
      index = field_indices[name]
      if max_index < index:
        max_index = index
    max_index += 1
    template = '''class %(typename)s(object):
        __slots__ = ("__values") \n
        _fields = %(field_names)r \n
        def __init__(self, values):
          self.__values = values
          if len(self.__values) <= %(max_index)s:
            for i in range(len(self.__values), %(max_index)s):
              self.__values += [None,]'''% locals()
    for name in field_names:
      index = field_indices[name]
      template += ''' \n
        @property
        def %s(self):
          return self.__values[%d]
        @%s.setter
        def %s(self, val):
          self.__values[%d] = val''' % (name, index, name, name, index)
    if verbose:
        print template

    # Execute the template string in a temporary namespace
    namespace = {'__name__':'namedtuple_%s' % typename,
        '_property':property, '_tuple':tuple}
    try:
        exec template  in namespace
    except SyntaxError, e:
        raise SyntaxError(e.message + ':\n' + template)
    result = namespace[typename]

    # For pickling to work, the __module__ variable needs to be set to the frame
    # where the named tuple is created.  Bypass this step in enviroments where
    # sys._getframe is not defined (Jython for example) or sys._getframe is not
    # defined for arguments greater than 0 (IronPython).
    try:
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
4

0 に答える 0