1

我在“datetime”的例子中停止它,在lxml的一个真实例子中重写。
(这可能很奇怪,因为英文是在谷歌翻译中翻译的,我很抱歉。)

据认为我喜欢 lxml 的性能非常好,但源代码很难阅读。
如果你积极使用XML,我也可以经常修改python的代码。
时间已经过去了,因为忘记了,源码因为很难理解,
我花时间调试和修复。
例如,我认为通常当您搜索如下:深层 XML 层次结构。

elem = lxml.etree.parse ("xxx/xxx/sample.xml").getroot()

elem.xpath("//depth3/text()")[0]

elem.find("./depth1/depth2/depth3").get("attr1").text

我想如下使用。
(使用此代码它只是我。)

elem.depth3.text (Ex.1)
OR
elem.depth1.depth2.depth3.text (Ex.2)

我试过类继承是先实现这个的。
您已经通过参考“在 lxml 中使用自定义元素类”进行了一些自定义。
我使用__getattr__来搜索 XML 元素。

from lxml import etree
class CustomElement (etree.ElementBase):
    def __ getattr__ (self, k):
        ret = self.xpath ("/ /" + k)
        setattr(self, k, ret)
        return getattr(self, k)

(Ex.1)成功的例子。
但是(Ex.2)的例子在etree._Element depth1的返回实例中变成了Attribute Error __getattr__is not present。

虽然不是(补充)实用,但我使用了一个示例,在 Easy to understand 的第一个问题中添加了“日期时间”的“毫秒”。

当时认为这是一种使用 ctypes 模块向 lxml 的 Element 类添加函数的方法。

import ctypes
import lxml.etree

class PyObject_HEAD(ctypes.Structure):
    _fields_ = [
        ('HEAD', ctypes.c_ubyte * (object.__basicsize__ -
                           ctypes.sizeof(ctypes.c_void_p))),
        ('ob_type', ctypes.c_void_p)
    ]
def __getattr__(self, k):
    ret = self.xpath("//" + k)
    setattr(self, k, ret)
    return getattr(self, k)

_get_dict          = ctypes.pythonapi._PyObject_GetDictPtr
_get_dict.restype  = ctypes.POINTER(ctypes.py_object)
_get_dict.argtypes = [ctypes.py_object]

EE = _get_dict(lxml.etree._Element).contents.value
EE["__getattr__"] = __getattr__

elem = lxml.etree.parse("xxx/xxx/sample.xml").getroot()
elem.xpath("//depth3")[0]

=> 返回 _Element 对象

from ispect import getsource
print getsource(elem.__getattr__)

=>def __getattr__(self, k):
=> ret = self.xpath("//" + k)
=> setattr(self, k, ret)
=> return getattr(self, k)
源被添加..

elem.depth3

=> AttributeError .. no attribute 'depth3'

我不知道是否或应该写如何使用“PyObject_GetAttr”。
请告诉我是否。

最好的问候


====================上一个问题========================== =========
我正在尝试增强 ctypes。添加功能通常很顺利。但是,如果添加特殊方法,它不起作用,为什么?

import ctypes as c

class PyObject_HEAD(c.Structure):
    _fields_ = [
        ('HEAD', c.c_ubyte * (object.__basicsize__ -
                              c.sizeof(c.c_void_p))),
        ('ob_type', c.c_void_p)
    ]

pgd = c.pythonapi._PyObject_GetDictPtr
pgd.restype = c.POINTER(c.py_object)
pgd.argtypes = [c.py_object]

import datetime

def millisecond(td):
    return (td.microsecond / 1000)

d = pgd(datetime.datetime)[0]
d["millisecond"] = millisecond

now = datetime.datetime.now()
print now.millisecond(), now.microsecond

这打印155 155958,好的!

def __getattr__(self, k):
    return self, k

d["__getattr__"] = __getattr__

now = datetime.datetime
print now.hoge

这不起作用,为什么?

Traceback (most recent call last):
  File "xxxtmp.py", line 31, in <module>
    print now.hoge
AttributeError: type object 'datetime.datetime' has no attribute 'hoge'
4

2 回答 2

0

我认为您不能__getattr__以这种方式覆盖。基本上,您正在破解对象__dict__以包含一个新方法。如果您调用now.millisecond,则调用原始的“属性获取器”,查看字典并返回您是新方法。我不确定这个属性 getter 驻留在哪里(可能在 C 代码中),但它不能在它查找内容的 dict 中 - 所以你不能以这种方式覆盖它。

可以试试__getattribute__,但我不知道这是否会奏效。请注意,正确实施要困难得多(请参阅https://stackoverflow.com/a/3278104/143091)。

话虽如此,以这种方式破解内置程序可能不是一个好主意。许多 python 标准库代码可能取决于您更改的行为,并且您的代码可能会以难以理解的方式失败。对于了解 python 并试图理解你的代码的人来说,这也会让人感到困惑。

我希望你不要从我这里得到这个讨厌的把戏。我使用它来向后移植旧版本的 python 或库中不可用的功能,例如:

if not hasattr(wnck.Screen, "get_workspaces"):
    def get_workspaces(screen):
        return [screen.get_workspace(i) for i in range(screen.get_workspace_count())]
        _get_dict(wnck.Screen)[0]['get_workspaces'] = get_workspaces

这样,我可以主要为现代版本的库进行开发,但如果只缺少一两个函数,我仍然支持旧版本,而无需更改我的代码。

于 2013-05-01T10:00:41.090 回答
0

PyObject_GetAttr(Objects/object.c) 使用类型的tp_getattro槽,或者tp_getattr如果前者没有定义。它不会__getattribute__在该类型的 MRO 中查找。

对于自定义__getattr__,您需要子类化datetime. 您的堆类型将使用slot_tp_getattr_hook(Objects/typeobject.c) 作为其tp_getattro. 该函数将通过调用(Objects/typeobject.c)在类型的 MRO 中查找__getattribute__和查找。__getattr___PyType_Lookup


鉴于您的更新,请参阅“在 lxml 中使用自定义元素类”。对于多个结果,我已经破解了一个__getattr__使用索引后缀表示法的钩子。否则默认为索引 0。诚然,我并没有考虑太多,但是如果您始终使用索引,则可以避免与现有名称发生冲突。

from lxml import etree

def make_parser(element):
    lookup = etree.ElementDefaultClassLookup(element=element)
    parser = etree.XMLParser()
    parser.setElementClassLookup(lookup)
    return parser

class CustomElement(etree.ElementBase):
    def __getattr__(self, attr):
        try:
            name, index = attr.rsplit('_', 1)
            index = int(index)
        except ValueError:
            name = attr
            index = 0
        return self.xpath(name)[index]

parser = make_parser(CustomElement)

例如:

>>> spam = etree.fromstring(r'''
... <spam>
...     <foo>
...         <bar>eggs00</bar>
...         <bar>eggs01</bar>
...     </foo>
...     <foo>
...         <bar>eggs10</bar>
...         <bar>eggs11</bar>
...     </foo>
... </spam>
... ''', parser)

>>> spam.foo_0.bar_0.text
'eggs00'
>>> spam.foo_0.bar_1.text
'eggs01'
>>> spam.foo_1.bar_0.text
'eggs10'
>>> spam.foo_1.bar_1.text
'eggs11'
于 2013-05-01T10:31:41.660 回答