如何为自定义类使用python集合

如何为自定义类使用python集合,python,data-structures,collections,abstract-data-type,functools,Python,Data Structures,Collections,Abstract Data Type,Functools,对于python及其神奇的函数式编程仍然有些困惑,因此我倾向于编写更倾向于Java编程范式的代码,而不是惯用python 我的问题与以下几点有关: 唯一的区别是我有嵌套对象(使用合成)。VirtualPage对象由PhysicalPage对象列表组成。我有一个函数,它可以获取physicalpage对象的列表,并将所有细节合并到一个命名元组中,我称之为PageBoundary。从本质上讲,它是一个序列化函数,可以输出一个元组,元组由一个整数范围组成,该范围表示物理页和页中的行号。由此,我可以轻松

对于python及其神奇的函数式编程仍然有些困惑,因此我倾向于编写更倾向于Java编程范式的代码,而不是惯用python

我的问题与以下几点有关:

唯一的区别是我有嵌套对象(使用合成)。VirtualPage对象由PhysicalPage对象列表组成。我有一个函数,它可以获取physicalpage对象的列表,并将所有细节合并到一个命名元组中,我称之为PageBoundary。从本质上讲,它是一个序列化函数,可以输出一个元组,元组由一个整数范围组成,该范围表示物理页和页中的行号。由此,我可以轻松地对虚拟页面进行排序和排序(至少是这样):

我还有一个函数,可以将名为tuple的PageBoundary反序列化或将tuple扩展到物理页面的列表中。最好不要更改这两个数据存储类,因为它会破坏任何下游代码

下面是我定制的python2.7类的一个片段。它由很多东西组成,一个是列表,其中包含一个对象物理页面

class VirtualPage(object):
    def __init__(self, _physical_pages=list()):
        self.physcial_pages = _physcial_pages


class PhysicalPage(object):
    # class variables: number of digits each attribute gets
    _PAGE_PAD, _LINE_PAD = 10, 12 

    def __init__(self, _page_num=-1):
        self.page_num = _page_num
        self.begin_line_num = -1
        self.end_line_num = -1

    def get_cannonical_begin(self):
        return int(''.join([str(self.page_num).zfill(PhysicalPage._PAGE_PAD),
                    str(tmp_line_num).zfill(PhysicalPage._LINE_PAD) ]))

    def get_cannonical_end(self):
        pass # see get_cannonical_begin() implementation

    def get_canonical_page_boundaries(self):
        return PageBoundary(self.get_canonical_begin(), self.get_canonical_end())
我想利用一些模板集合(来自python集合模块)来轻松地排序和比较VirtualPage类的列表或集合。我还想了解一些关于我的数据存储类布局的建议:VirtualPagePhysicalPage

给定一系列虚拟页面,或如以下示例所示:

vp_1 = VirtualPage(list_of_physical_pages)
vp_1_copy = VirtualPage(list_of_physical_pages)
vp_2 = VirtualPage(list_of_other_physical_pages)
我想简单地回答如下问题:

>>> vp_2 in vp_1 
False
>>> vp_2 < vp_1
True
>>> vp_1 == vp_1_copy
True
2.)比较函数实现是否应该存在于VirtualPage类中


我倾向于某种类型的集合数据结构,因为我正在建模的数据的属性具有唯一性的概念:即物理页面值不能重叠,并在某种程度上充当链接列表。另外,通过@decorator函数实现的setter或getter函数在这里也有用吗?

我想您需要下面的代码。未经测试;当然没有针对您的应用程序或数据、YMMV等进行测试

from collections import namedtuple

# PageBoundary is a subclass of named tuple with special relational
# operators. __le__ and __ge__ are left undefined because they don't
# make sense for this class.
class PageBoundary(namedtuple('PageBoundary', 'begin end')):
    # to prevent making an instance dict (See namedtuple docs)
    __slots__ = ()

    def __lt__(self, other):
        return self.end < other.begin

    def __eq__(self, other):
        # you can put in an assertion if you are concerned the
        # method might be called with the wrong type object
        assert isinstance(other, PageBoundary), "Wrong type for other"

        return self.begin == other.begin and self.end == other.end

    def __ne__(self, other):
        return not self == other

    def __gt__(self, other):
        return other < self


class PhysicalPage(object):
    # class variables: number of digits each attribute gets
    _PAGE_PAD, _LINE_PAD = 10, 12 

    def __init__(self, page_num):
        self.page_num = page_num

        # single leading underscore is 'private' by convention
        # not enforced by the language
        self._begin = self.page_num * 10**PhysicalPage._LINE_PAD + tmp_line_num
        #self._end = ...however you calculate this...                    ^ not defined yet

        self.begin_line_num = -1
        self.end_line_num = -1

    # this serves the purpose of a `getter`, but looks just like
    # a normal class member access. used like x = page.begin  
    @property
    def begin(self):
        return self._begin

    @property
    def end(self):
        return self._end

    def __lt__(self, other):
        assert(isinstance(other, PhysicalPage))
        return self._end < other._begin

    def __eq__(self, other):
        assert(isinstance(other, PhysicalPage))
        return self._begin, self._end == other._begin, other._end

    def __ne__(self, other):
        return not self == other

    def __gt__(self, other):
        return other < self


class VirtualPage(object):
    def __init__(self, physical_pages=None):
        self.physcial_pages = sorted(physcial_pages) if physical_pages else []

    def __lt__(self, other):
        if self.physical_pages and other.physical_pages:
            return self.physical_pages[-1].end < other.physical_pages[0].begin

        else:
            raise ValueError

    def __eq__(self, other):
        if self.physical_pages and other.physical_pages:
            return self.physical_pages == other.physical_pages

        else:
            raise ValueError

    def __gt__(self, other):
        return other < self
从集合导入namedtuple
#PageBoundary是命名元组的一个子类,具有特殊的关系类型
#接线员__le______________________________________
#对这门课有意义。
类PageBoundary(名称为tuple('PageBoundary','begin end')):
#防止生成实例dict(请参阅namedtuple文档)
__插槽\uuux=()
定义(自身、其他):
返回self.end
以及一些观察结果:

虽然Python类中没有“private”成员这类东西,但惯例是在变量名的开头加上一个下划线,
,以表示它不是类/模块/等的公共接口的一部分。因此,用“u”命名公共方法的方法参数似乎不正确,例如,
def_uinit__(self,_page_num=-1)

Python通常不使用setter/getter;直接使用属性即可。如果需要计算属性值,或者需要其他处理,请使用
@property
装饰器(如上面的PhysicalPage.begin()所示)

使用可变对象初始化默认函数参数通常不是一个好主意。
def uuu init uuu(self,physical_pages=list())
不会每次使用新的空列表初始化物理页面,而是每次使用相同的列表。如果列表被修改,在下一次函数调用时,物理页面将使用modif初始化
import collections as col
import functools

@total_ordering
class AbstractVirtualPageContainer(col.MutableSet):

    def __lt__(self, other):
        '''What type would other be?
        Make comparison by first normalizing to a comparable type: PageBoundary
        '''
        pass
from collections import namedtuple

# PageBoundary is a subclass of named tuple with special relational
# operators. __le__ and __ge__ are left undefined because they don't
# make sense for this class.
class PageBoundary(namedtuple('PageBoundary', 'begin end')):
    # to prevent making an instance dict (See namedtuple docs)
    __slots__ = ()

    def __lt__(self, other):
        return self.end < other.begin

    def __eq__(self, other):
        # you can put in an assertion if you are concerned the
        # method might be called with the wrong type object
        assert isinstance(other, PageBoundary), "Wrong type for other"

        return self.begin == other.begin and self.end == other.end

    def __ne__(self, other):
        return not self == other

    def __gt__(self, other):
        return other < self


class PhysicalPage(object):
    # class variables: number of digits each attribute gets
    _PAGE_PAD, _LINE_PAD = 10, 12 

    def __init__(self, page_num):
        self.page_num = page_num

        # single leading underscore is 'private' by convention
        # not enforced by the language
        self._begin = self.page_num * 10**PhysicalPage._LINE_PAD + tmp_line_num
        #self._end = ...however you calculate this...                    ^ not defined yet

        self.begin_line_num = -1
        self.end_line_num = -1

    # this serves the purpose of a `getter`, but looks just like
    # a normal class member access. used like x = page.begin  
    @property
    def begin(self):
        return self._begin

    @property
    def end(self):
        return self._end

    def __lt__(self, other):
        assert(isinstance(other, PhysicalPage))
        return self._end < other._begin

    def __eq__(self, other):
        assert(isinstance(other, PhysicalPage))
        return self._begin, self._end == other._begin, other._end

    def __ne__(self, other):
        return not self == other

    def __gt__(self, other):
        return other < self


class VirtualPage(object):
    def __init__(self, physical_pages=None):
        self.physcial_pages = sorted(physcial_pages) if physical_pages else []

    def __lt__(self, other):
        if self.physical_pages and other.physical_pages:
            return self.physical_pages[-1].end < other.physical_pages[0].begin

        else:
            raise ValueError

    def __eq__(self, other):
        if self.physical_pages and other.physical_pages:
            return self.physical_pages == other.physical_pages

        else:
            raise ValueError

    def __gt__(self, other):
        return other < self