如何在Python中更改作为类属性实现的列表的返回/输入类型? [英] How can I change in Python the return/input type of a list that is implemented as an class attribute?

查看:55
本文介绍了如何在Python中更改作为类属性实现的列表的返回/输入类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑(该问题的完整表述为原始版本(请参阅原始版本",稍后)是误导性的):

这里是设置:我有一个对象,该对象具有类型的对象列表 <class 'One'>.我想访问此列表,而是使用对象 类型为<class 'Two'>的类型,它是<class 'One'>的增强版本.

Here is the setting: I have a object which has a list of objects of type <class 'One'>. I would like to access this list but rather work with objects of type <class 'Two'> which is an enriched version of <class 'One'>.

背景(1):

  • One可以是可以通过ORM轻松存储的对象. ORM将根据数据模型处理列表
  • Two会是与One类似的对象,但会通过许多功能或可访问的方式丰富
  • One could be an object that can be stored easily via a ORM. The ORM would handle the list depending on the data model
  • Two would be an object like One but enriched by many features or the way it can be accessed

背景(2):

  • 我尝试解决我问过的与SQLAlchemy相关的问题
  • I try to solve a SQLAlchemy related question that I asked here. So, the answer to the present question could be also a solution to that question changing return/input type of SQLAlchemy-lists.

以下是一些说明代码:

import numpy as np

class One(object):
  """
  Data Transfere Object (DTO)
  """
  def __init__(self, name, data):
    assert type(name) == str
    assert type(data) == str
    self.name = name
    self.data = data

  def __repr__(self):
    return "%s(%r, %r)" %(self.__class__.__name__, self.name, self.data)

class Two(np.ndarray):
  _DTO = One
  def __new__(cls, name, data):
    dto = cls._DTO(name, data)
    return cls.newByDTO(dto)

  @classmethod
  def newByDTO(cls, dto):
    obj = np.fromstring(dto.data, dtype="float", sep=',').view(cls)
    obj.setflags(write=False) # Immutable
    obj._dto = dto
    return obj

  @property
  def name(self):
    return self._dto.name

class DataUI(object):
  def __init__(self, list_of_ones):
    for one in list_of_ones:
      assert type(one) == One
    self.list_of_ones = list_of_ones

if __name__ == '__main__':
  o1 = One('first object', "1, 3.0, 7, 8,1")
  o2 = One('second object', "3.7, 8, 10")
  my_data = DataUI ([o1, o2])

如何实现在list_of_ones上运行但向用户提供具有Two类型元素的列表的list_of_twos:

How to implement a list_of_twos which operates on list_of_ones but provides the user a list with elements of type Two:

type (my_data.list_of_twos[1]) == Two
>>> True
my_data.list_of_twos.append(Two("test", "1, 7, 4.5"))
print my_data.list_of_ones[-1]
>>> One('test', '1, 7, 4.5')


问题的原始版本:

以下是问题的说明:

class Data(object):
    def __init__(self, name, data_list):
        self.name = name
        self.data_list = data_list

if __name__ == '__main__':
    my_data = Data ("first data set", [0, 1, 1.4, 5])

我想通过另一个将列表元素作为其他类型(例如numpy.ndarray)处理的列表(例如my_data.data_np_list)访问my_data.data_list:

I would like to access my_data.data_list via another list (e.g. my_data.data_np_list) that handles list-elements as a different type (e.g. as numpy.ndarray):

>>> my_data.data_np_list[1]
array(1)
>>> my_data.data_np_list.append(np.array(7))
>>> print my_data.data_list
[0, 1, 1.4, 5, 7]

推荐答案

我刚想到的一个解决方案是通过类ListView实现列表视图,该类采用以下参数:

One solution I just came up with would be to implement a View of the list via class ListView which takes the following arguments:

  • raw_list:One-对象的列表
  • raw2new:将One-对象转换为Two-对象
  • 的函数
  • new2raw:将Two-对象转换为One-对象
  • 的函数
  • raw_list: a list of One-objects
  • raw2new: a function that converts One-objects to Two-objects
  • new2raw: a function that converts Two-objects to One-objects

这是一个代码:

class ListView(list):
  def __init__(self, raw_list, raw2new, new2raw):
    self._data = raw_list
    self.converters = {'raw2new': raw2new,
        'new2raw': new2raw}

  def __repr__(self):
    repr_list = [self.converters['raw2new'](item) for item in self._data]
    repr_str = "["
    for element in repr_list:
      repr_str += element.__repr__() + ",\n "
    repr_str = repr_str[:-3] + "]"
    return repr_str

  def append(self, item):
    self._data.append(self.converters['new2raw'](item))

  def pop(self, index):
    self._data.pop(index)

  def __getitem__(self, index):
    return self.converters['raw2new'](self._data[index])

  def __setitem__(self, key, value):
    self._data.__setitem__(key, self.converters['new2raw'](value))

  def __delitem__(self, key):
    return self._data.__delitem__(key)

  def __getslice__(self, i, j):
    return ListView(self._data.__getslice__(i,j), **self.converters)

  def __contains__(self, item):
    return self._data.__contains__(self.converters['new2raw'](item))

  def __add__(self, other_list_view):
    assert self.converters == other_list_view.converters
    return ListView(
        self._data + other_list_view._data,
        **self.converters
        )

  def __len__(self):
    return len(self._data)

  def __eq__(self, other):
    return self._data == other._data

  def __iter__(self):
    return iter([self.converters['raw2new'](item) for item in self._data])

现在,DataUI必须看起来像这样:

Now, DataUI has to look something like this:

class DataUI(object):
  def __init__(self, list_of_ones):
    for one in list_of_ones:
      assert type(one) == One
    self.list_of_ones = list_of_ones
    self.list_of_twos = ListView(
        self.list_of_ones,
        Two.newByDTO,
        Two.getDTO
        )

为此,Two需要以下方法:

def getDTO(self):
  return self._dto

整个示例现在如下所示:

The entire example would now look like the following:

import unittest
import numpy as np

class ListView(list):
  def __init__(self, raw_list, raw2new, new2raw):
    self._data = raw_list
    self.converters = {'raw2new': raw2new,
        'new2raw': new2raw}

  def __repr__(self):
    repr_list = [self.converters['raw2new'](item) for item in self._data]
    repr_str = "["
    for element in repr_list:
      repr_str += element.__repr__() + ",\n "
    repr_str = repr_str[:-3] + "]"
    return repr_str

  def append(self, item):
    self._data.append(self.converters['new2raw'](item))

  def pop(self, index):
    self._data.pop(index)

  def __getitem__(self, index):
    return self.converters['raw2new'](self._data[index])

  def __setitem__(self, key, value):
    self._data.__setitem__(key, self.converters['new2raw'](value))

  def __delitem__(self, key):
    return self._data.__delitem__(key)

  def __getslice__(self, i, j):
    return ListView(self._data.__getslice__(i,j), **self.converters)

  def __contains__(self, item):
    return self._data.__contains__(self.converters['new2raw'](item))

  def __add__(self, other_list_view):
    assert self.converters == other_list_view.converters
    return ListView(
        self._data + other_list_view._data,
        **self.converters
        )

  def __len__(self):
    return len(self._data)

  def __iter__(self):
    return iter([self.converters['raw2new'](item) for item in self._data])

  def __eq__(self, other):
    return self._data == other._data


class One(object):
  """
  Data Transfere Object (DTO)
  """
  def __init__(self, name, data):
    assert type(name) == str
    assert type(data) == str
    self.name = name
    self.data = data

  def __repr__(self):
    return "%s(%r, %r)" %(self.__class__.__name__, self.name, self.data)


class Two(np.ndarray):
  _DTO = One
  def __new__(cls, name, data):
    dto = cls._DTO(name, data)
    return cls.newByDTO(dto)

  @classmethod
  def newByDTO(cls, dto):
    obj = np.fromstring(dto.data, dtype="float", sep=',').view(cls)
    obj.setflags(write=False) # Immutable
    obj._dto = dto
    return obj

  @property
  def name(self):
    return self._dto.name

  def getDTO(self):
    return self._dto


class DataUI(object):
  def __init__(self, list_of_ones):
    for one in list_of_ones:
      assert type(one) == One
    self.list_of_ones = list_of_ones
    self.list_of_twos = ListView(
        self.list_of_ones,
        Two.newByDTO,
        Two.getDTO
        )


class TestListView(unittest.TestCase):
  def testProperties(self):
    o1 = One('first object', "1, 3.0, 7, 8,1")
    o2 = One('second object', "3.7, 8, 10")
    my_data = DataUI ([o1, o2])

    t1 = Two('third object', "4.8, 8.2, 10.3")
    t2 = Two('forth object', "33, 1.8, 1.0")
    # append:
    my_data.list_of_twos.append(t1)
    # __getitem__:
    np.testing.assert_array_equal(my_data.list_of_twos[2], t1)
    # __add__:
    np.testing.assert_array_equal(
        (my_data.list_of_twos + my_data.list_of_twos)[5], t1)
    # __getslice__:
    np.testing.assert_array_equal(
        my_data.list_of_twos[1:],
        my_data.list_of_twos[1:2] + my_data.list_of_twos[2:]
        )
    # __contains__:
    self.assertEqual(my_data.list_of_twos.__contains__(t1), True)
    # __setitem__:
    my_data.list_of_twos.__setitem__(1, t1),
    np.testing.assert_array_equal(my_data.list_of_twos[1], t1)
    # __delitem__:
    l1 = len(my_data.list_of_twos)
    my_data.list_of_twos.__delitem__(1)
    l2 = len(my_data.list_of_twos)
    self.assertEqual(l1 - 1, l2)
    # __iter__:
    my_data_2 = DataUI ([])
    for two in my_data.list_of_twos:
      my_data_2.list_of_twos.append(two)


if __name__ == '__main__':
  unittest.main()

这篇关于如何在Python中更改作为类属性实现的列表的返回/输入类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆