【问题标题】:TypeError: cannot deepcopy this pattern objectTypeError:无法深复制此模式对象
【发布时间】:2011-09-10 21:07:43
【问题描述】:

试图在我的“变量”类中理解这个错误。

我希望在我的“变量”类中存储一个 sre.SRE_Pattern。我刚开始复制变量类,并注意到它导致我所有的变量类实例都发生了变化。我现在明白我需要对这个类进行深度复制,但现在我遇到了“TypeError:无法深度复制这个模式对象”。当然,我可以将模式存储为文本字符串,但我的其余代码已经期望编译模式!用模式对象复制我的变量类的最佳方法是什么?

import re
from copy import deepcopy

class VariableWithRE(object):
    "general variable class"
    def __init__(self,name,regexTarget,type):
        self.name = name
        self.regexTarget = re.compile(regexTarget, re.U|re.M) 
        self.type = type 

class VariableWithoutRE(object):
    "general variable class"
    def __init__(self,name,regexTarget,type):
        self.name = name
        self.regexTarget = regexTarget
        self.type = type 

if __name__ == "__main__":

    myVariable = VariableWithoutRE("myName","myRegexSearch","myType")
    myVariableCopy = deepcopy(myVariable)

    myVariable = VariableWithRE("myName","myRegexSearch","myType")
    myVariableCopy = deepcopy(myVariable)

【问题讨论】:

  • 鉴于编译器正则表达式是不可变的,没有必要对其进行深度复制。但是我不记得如何告诉deepcopy() 如何处理特定类型(但请注意,如果需要,您可以向内置类型添加属性)。
  • 代码中的哪一行抛出异常?我已经复制了它然后编译->它在我身边没有任何错误。我发现的唯一一件事是你尝试使用重写 python 方法'type'的变量,这不是很好的风格。
  • 最后一行在 Python 2.6 中为我抛出了错误。

标签: python regex deep-copy


【解决方案1】:

如果您的此类(及其子类_)的实例不需要深拷贝,但只会导致问题,因为它们是确实需要深拷贝,那么你可以这样做:

#might as well limit this hack to versions that need it...
if sys.version_info <= (3, 7):

    def __deepcopy__(self, *args, **kwargs):
        """ cheat here because regex can't be deepcopied"""
        return self

现在,您需要小心。我正在做的假设。如果您开始更改此类的任何实例,则可能会出现副作用,因为实际上并未发生深拷贝。仅当您在其他地方需要 deepcopy 并且您很确定自己不关心 this 类和 deepcopy 时才值得。

【讨论】:

    【解决方案2】:

    这可以通过在 3.7 之前的 python 中修补 copy 模块来解决:

    import copy
    import re 
    
    copy._deepcopy_dispatch[type(re.compile(''))] = lambda r, _: r
    
    o = re.compile('foo')
    assert copy.deepcopy(o) == o
    

    【讨论】:

    • 这会创建一个新实例吗?从我的测试来看,它看起来像,但代码表明它是同一个实例?
    • @MarkusRessel:它没有——如assert copy.deepcopy(o) is o 所示。你是怎么测试的?
    • 你是对的,我的测试是错误的。 re.compile() 方法有一个内置缓存,所以即使在 lambda 中使用类似 re.compile(r.pattern) 的东西,如果模式(和标志)相同,也不会创建新实例。我想知道这是否也是在 python 3.7 中完成的。
    • 它实际上是相同的(即:复制被实现为身份)但在 re 模块的本机代码中实现:github.com/python/cpython/commit/…
    【解决方案3】:

    这似乎已在 Python 3.7+ 版本中得到修复:

    现在可以使用 copy.copy() 和 copy.deepcopy() 复制已编译的正则表达式和匹配对象。 (由 Serhiy Storchaka 在 bpo-10076 中贡献。)

    根据:https://docs.python.org/3/whatsnew/3.7.html#re

    测试:

    import re,copy
    
    class C():
        def __init__(self):
           self.regex=re.compile('\d+')
    
    myobj = C()    
    foo = copy.deepcopy(myobj)
    foo.regex == myobj.regex
    # True
    

    【讨论】:

      【解决方案4】:

      问题似乎是编译的正则表达式。 deepcopy 无法处理它们。

      一个最小的例子给了我同样的错误:

      import re,copy
      class C():
          def __init__(self):
              self.regex=re.compile('\d+')
      
      myobj = C()    
      copy.deepcopy(myobj)
      

      这会引发错误:TypeError: cannot deepcopy this pattern object。我在python3.5。

      【讨论】:

      • 我也有同样的问题
      【解决方案5】:

      deepcopy 对您的课程一无所知,也不知道如何复制它们。

      您可以通过实现__deepcopy__() 方法告诉deepcopy 如何复制您的对象:

      class VariableWithoutRE(object):
         # ...
         def __deepcopy__(self):
            return VariableWithoutRE(self.name, self.regexTarget, self.type)
      

      【讨论】:

      • 问题是复制VariableWithRE,所以你的例子并没有真正的帮助,但它朝着正确的方向发展。
      • 我在我的两个课程中都尝试过这种方法,首先我得到“TypeError: __deepcopy__() 只需要 1 个参数(给定 2 个)”,然后我查看了 this 问题,并尝试了“def __deepcopy__(self,memo):"。语法对我来说似乎很奇怪,因为有人还在学习 Python,但是好的,备忘录,很好。这在 VariableWithoutRE 类中有效,但在 VariableWithRE 类中仍然存在问题!新错误:“ValueError:无法使用已编译模式处理标志参数”
      • @user789215 问题是您正在使用已编译的正则表达式 (self.regexTarget) 调用 VariableWithoutRE 构造函数 (init),而构造函数需要一个字符串。
      猜你喜欢
      • 2021-02-16
      • 2019-05-11
      • 1970-01-01
      • 2017-10-23
      • 2019-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多