保持Python中包装类的平等和身份

2024-09-30 06:17:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我希望为我的用例找到一些指向“最佳实践”的指针

我试图回答的问题(本质上)是:

Is it considered poor practice when there is a class Wrapper which is a wrapper for another class Wrapped that there could be two distinct Wrapper objects which wrap the same instance of a Wrapped object?

我的想法是,我使用包装器类来更改(实际上是简化)对象的接口,但包装的对象是数据的真正所有者。因此,我不希望包装器类混淆或误导用户对底层对象的理解

在我的用例上下文中描述这个问题可能是最容易的

我的用例

我正在编写一个应用程序(Python),它将处理用户提供的大纲文件,并执行一些增值功能来丰富其中包含的数据

大纲是大纲应用程序(如Mac上的OmniOutliner)、思维导图应用程序(如MindManager)用于新闻联合和许多其他用途的层次结构

大纲文件存储为OPML(大纲处理标记语言),这是一种XML语言(http://dev.opml.org/)。OPML文件在结构的顶部包含一些元素(<opml><head><body>),但是所有数据都包含在带有属性的<outline>元素的层次结构中

我的实现

Python中没有可用的OPML解析器库(据我所知),因此在我为我的应用程序开发功能时,我打算使我的OPML解析模块独立,以便将其制作成一个包供一般使用。因此,我渴望使它符合被认为是良好的一般做法,特别是要确保它是Pythonic

我正在使用xml.etree(ElementTree,Element)

https://docs.python.org/3.7/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element

…以处理XML文件

在xmltree中,Element类用于存储通用XML元素,并存储其标记名、各种其他字段和子节点

对于我的实现,我写了:

  • 表示整个OPML数据结构的类,称为Outline
  • 一个称为OutlineNode的包装器(适配器设计模式)类,它包装Element类(它存储在私有属性_node)以表示大纲中的每个<outline>元素

    OutlineNode为用户提供了一个简单的界面来访问<outline>元素中的信息,但隐藏了Element类提供的附加功能,该类被设计为通用XML节点表示

    例如,每个<outline>元素可以包括一个“text”属性和一个“_note”属性,用户可以通过OutlineNode对象的属性使用该属性

    一个OutlineNode的孩子也是OutlineNodes

例如,当用户请求OutlineNode对象的子对象时,我的代码:

  • 访问基础(已包装)Element节点
  • 使用Element中内置的功能获取其子级
  • 返回每个包装在新创建的OutlineNode对象中的子对象

问题

这种方法在功能上非常有效,但有几个问题困扰着我:

  1. 第一个问题是,每次我请求节点的子节点时,动态创建OutlineNodes并不是一种非常有效的方法(可以说),但它很简单,效果很好。我没有注意到任何性能问题,几乎可以肯定这对我来说不会是一个大问题,因为我的应用程序通常只解析一次文件。如果我想编写一个通用的OPML处理库,这可能不太好,这让我很恼火

  2. 第二个是,如果用户访问一个节点的子节点两次,而它们将存储相同的底层Element节点,那么包装它们的OutlineNode对象将被动态创建,因此将是不同的物理对象

    我已经覆盖了OutlineNode中的__eq__(),所以有两个OutlineNode在下面包装相同的内容躺着的Element是相等的,但这两个OutlineNode将不是相同的对象

因此,我可以编写如下代码:

child_1 = parent_node[0] # Accesses the first child of an OutlineNode object
child_2 = parent_node[0] # Accesses the same child for a second time

assert(child_1._node is child_2._node)
assert(child_1 == child_2)
assert(child_1 is child_2)

以及:

  • 第一个断言将成功,因为底层Element对象(_node)是同一个对象
  • 第二个断言将成功,因为如果两个比较的OutlineNode对象的{u节点属性都是相同的对象,则我已重写__eq__以返回True
  • 第三个断言将失败,因为我的代码为child_1child_2的每个赋值创建了一个新的OutlineNode对象

所以我有三个问题:

  • 我是否只需要接受这样一个事实:通过使用包装器类,我不能保证代码提供给用户的对象(包装相同的底层XML节点)始终是相同的物理对象。我担心这可能会产生误导和混淆
  • 这是包装器设计模式的公认问题吗?是否有公认的处理方法
  • 当我从Element创建OutlineNode实例并始终向用户提供相同的实例时,我是否应该实现某种跟踪机制?这将使我的代码变得非常复杂,目前代码非常简单

欢迎提出意见和建议


Tags: 文件对象代码用户功能nodechild元素

热门问题