【问题标题】:python-docx library - How to extend the class "Document'python-docx 库 - 如何扩展“文档”类
【发布时间】:2020-08-06 09:21:33
【问题描述】:

在python-docx库中,Document对象是使用docx.api文件中的构造函数func:docx.Document创建的

def Document(docx=None):
"""
Return a |Document| object loaded from *docx*, where *docx* can be
either a path to a ``.docx`` file (a string) or a file-like object. If
*docx* is missing or ``None``, the built-in default document "template"
is loaded.
"""
docx = _default_docx_path() if docx is None else docx
document_part = Package.open(docx).main_document_part
if document_part.content_type != CT.WML_DOCUMENT_MAIN:
    tmpl = "file '%s' is not a Word file, content type is '%s'"
    raise ValueError(tmpl % (docx, document_part.content_type))
return document_part.document

但是可以应用于对象的方法位于文件 docx.document.Document 中。下面是截图

类文档(ElementProxy): """WordprocessingML (WML) 文档。

Not intended to be constructed directly. Use :func:`docx.Document` to open or create
a document.
"""

__slots__ = ('_part', '__body')

def __init__(self, element, part):
    super(Document, self).__init__(element)
    self._part = part
    self.__body = None

def add_heading(self, text="", level=1):
    """Return a heading paragraph newly added to the end of the document.

    The heading paragraph will contain *text* and have its paragraph style
    determined by *level*. If *level* is 0, the style is set to `Title`. If *level*
    is 1 (or omitted), `Heading 1` is used. Otherwise the style is set to `Heading
    {level}`. Raises |ValueError| if *level* is outside the range 0-9.
    """
    if not 0 <= level <= 9:
        raise ValueError("level must be in range 0-9, got %d" % level)
    style = "Title" if level == 0 else "Heading %d" % level
    return self.add_paragraph(text, style)

def add_page_break(self):
    """Return newly |Paragraph| object containing only a page break."""
    paragraph = self.add_paragraph()
    paragraph.add_run().add_break(WD_BREAK.PAGE)
    return paragraph

def add_paragraph(self, text='', style=None):
    """
    Return a paragraph newly added to the end of the document, populated
    with *text* and having paragraph style *style*. *text* can contain
    tab (``\\t``) characters, which are converted to the appropriate XML
    form for a tab. *text* can also include newline (``\\n``) or carriage
    return (``\\r``) characters, each of which is converted to a line
    break.
    """
    return self._body.add_paragraph(text, style)

我想了解 - 如何在函数创建的对象上使用类 Document 的方法 - docx.Document 。两者之间的联系是什么?

另外,如何使用新方法扩展类 Document 并将其应用于由函数创建的对象。例如 - 下面不起作用

from docx.document import Document as doc1
class doc_new(doc1):
    def new_prop(self, q):
        self.name = q
        return self.name

document = Document()
x = document.new_prop("John")
print(x)

【问题讨论】:

    标签: python python-docx


    【解决方案1】:

    docx.Document()函数返回的Document对象是在docx.parts.document.DocumentPart.document()方法中创建的:
    https://github.com/python-openxml/python-docx/blob/master/docx/parts/document.py#L47-L52

    因此,它像任何其他 Document 对象一样通过使用文档的主要 XML 元素调用类来创建。

    由于该对象是Document 实例,它具有docx.document.Document 类上定义的所有方法和属性。

    Document 对象的构造不那么直接,因为这使得 API 在大多数情况下都易于使用。如果是直接的,用户将不得不自己挖掘 XML 元素,而且很多事情会变得比 99.9% 的用户需要的复杂得多。

    就扩展Document 的功能而言,我可以看到您有三个主要选择:

    1. 创建python-pptx 的分支并编辑docx.document.Document 类以适应任何情况,以及任何从属类,如Paragraph 等。

    2. “包装”(又名。Compose)一个文档对象与您自己的对象,该对象添加自己的功能并通过其他调用传递到底层文档对象。

      有很多理由比第一种更喜欢第二种方法,主要是因为它的工作量要少得多。相同的组合策略也适用于段落等较低级别的对象。

    3. 编写将文档作为第一个参数并执行您想要的操作的函数。这有点像Document 对象的“无实体”方法。所有Document 方法都是将Document 对象作为第一个参数(self) 的函数,因此您可以通过这种方式完成方法的大部分功能。

      这是迄今为止最简单的方法,大多数人都这样做,也是我推荐的方法(并自己使用)。

    【讨论】:

    • 谢谢。但是你怎么知道文档对象是由 docx.parts.document.DocumentPart 创建的。我无法从以下函数中找到它。
    • document_part 是从Package.open 获得的DocumentPart 对象。如果您检查DocumentPart.document,您会看到它调用docx.document.Document 构造函数,它在构造时从Package.open() 接收到的文档的根XML 元素。
    • @scanny 你怎么做选项2?我尝试使用 docx.document、docx.document.Document 等定义一个类,但没有一个允许我在方法中执行 self.add_paragraph。
    • @StevenBrown 如果您创建一个单独的问题并包含您尝试过但不起作用的代码,我会看看。确保用python-docx 标记它,我会看到它。
    【解决方案2】:

    谢谢。但是你怎么知道文档对象是由 docx.parts.document.DocumentPart 创建的。我无法从以下函数中找到它。

    '''
    def Document(docx=None):
    """
    Return a |Document| object loaded from *docx*, where *docx* can be
    either a path to a ``.docx`` file (a string) or a file-like object. If
    *docx* is missing or ``None``, the built-in default document "template"
    is loaded.
    """
    docx = _default_docx_path() if docx is None else docx
    document_part = Package.open(docx).main_document_part
    if document_part.content_type != CT.WML_DOCUMENT_MAIN:
        tmpl = "file '%s' is not a Word file, content type is '%s'"
        raise ValueError(tmpl % (docx, document_part.content_type))
    return document_part.document
    
    '''
    

    【讨论】:

    • 您的回复应该是对我的回答的评论,而不是单独的回答。我知道评论空间有限,但答案是为了答案:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-01
    • 1970-01-01
    • 2022-11-21
    • 2021-12-25
    相关资源
    最近更新 更多