【问题标题】:How can I simply inherit methods from an existing instance?如何简单地从现有实例继承方法?
【发布时间】:2010-09-07 10:32:31
【问题描述】:

下面我有一个非常简单的例子来说明我正在尝试做的事情。我希望能够将 HTMLDecorator 与任何其他类一起使用。忽略它被称为装饰器的事实,它只是一个名字。

import cgi

class ClassX(object):
  pass # ... with own __repr__

class ClassY(object):
  pass # ... with own __repr__

inst_x=ClassX()

inst_y=ClassY()

inst_z=[ i*i for i in range(25) ]

inst_b=True

class HTMLDecorator(object):
   def html(self): # an "enhanced" version of __repr__
       return cgi.escape(self.__repr__()).join(("<H1>","</H1>"))

print HTMLDecorator(inst_x).html()
print HTMLDecorator(inst_y).html()
wrapped_z = HTMLDecorator(inst_z)
inst_z[0] += 70
wrapped_z[0] += 71
print wrapped_z.html()
print HTMLDecorator(inst_b).html()

输出:

Traceback(最近一次调用最后一次):
  文件“html.py”,第 21 行,在
    打印 HTMLDecorator(inst_x).html()
TypeError: default __new__ 不带参数

我正在尝试做的事情可能吗?如果是这样,我做错了什么?

【问题讨论】:

    标签: python oop inheritance object


    【解决方案1】:

    非常接近,但后来我失去了 ClassX 的一切。下面是一位同事给我的东西,它确实可以解决问题,但它很可怕。必须有更好的方法。

    看起来您正在尝试设置某种代理对象方案。这是可行的,并且有比你同事更好的解决方案,但首先要考虑是否只用一些额外的方法进行修补会更容易。这不适用于像 bool 这样的内置类,但它适用于您的用户定义类:

    def HTMLDecorator (obj):
        def html ():
            sep = cgi.escape (repr (obj))
            return sep.join (("<H1>", "</H1>"))
        obj.html = html
        return obj
    

    这是代理版本:

    class HTMLDecorator(object):
        def __init__ (self, wrapped):
            self.__wrapped = wrapped
    
        def html (self):
            sep = cgi.escape (repr (self.__wrapped))
            return sep.join (("<H1>", "</H1>"))
    
        def __getattr__ (self, name):
            return getattr (self.__wrapped, name)
    
        def __setattr__ (self, name, value):
            if not name.startswith ('_HTMLDecorator__'):
                setattr (self.__wrapped, name, value)
                return
            super (HTMLDecorator, self).__setattr__ (name, value)
    
        def __delattr__ (self, name):
            delattr (self.__wraped, name)
    

    【讨论】:

      【解决方案2】:

      John 的两种解决方案都有效。另一个允许 HTMLDecorator 保持非常简单和干净的选项是将其作为基类进行猴子修补。这也仅适用于用户定义的类,不适用于内置类型:

      import cgi
      
      class ClassX(object):
          pass # ... with own __repr__
      
      class ClassY(object):
          pass # ... with own __repr__
      
      inst_x=ClassX()
      inst_y=ClassY()
      
      class HTMLDecorator:
          def html(self): # an "enhanced" version of __repr__
              return cgi.escape(self.__repr__()).join(("<H1>","</H1>"))
      
      ClassX.__bases__ += (HTMLDecorator,)
      ClassY.__bases__ += (HTMLDecorator,)
      
      print inst_x.html()
      print inst_y.html()
      

      但请注意——像这样的猴子补丁会在代码的可读性和可维护性方面付出高昂的代价。当你一年后回到这段代码时,可能很难弄清楚你的 ClassX 是如何得到那个 html() 方法的,尤其是如果 ClassX 是在其他库中定义的。

      【讨论】:

        【解决方案3】:

        我正在尝试做的事情可能吗?如果是这样,我做错了什么?

        这当然是可能的。问题是HTMLDecorator.__init__() 不接受参数。

        这是一个简单的例子:

        def decorator (func):
            def new_func ():
                return "new_func %s" % func ()
            return new_func
        
        @decorator
        def a ():
            return "a"
        
        def b ():
            return "b"
        
        print a() # new_func a
        print decorator (b)() # new_func b
        

        【讨论】:

          【解决方案4】:

          @约翰(37448):

          对不起,我可能用这个名字误导了你(错误的选择)。我并不是真的在寻找装饰器功能,或者根本不是与装饰器有关的任何事情。我所追求的是 html(self) def 使用 ClassX 或 ClassY 的__repr__。我希望它能够在不修改 ClassX 或 ClassY 的情况下工作。

          【讨论】:

            【解决方案5】:

            啊,在那种情况下,也许这样的代码会有用?它实际上与装饰器没有任何关系,但演示了如何将参数传递给类的初始化函数并检索这些参数以供以后使用。

            import cgi
            
            class ClassX(object):
                def __repr__ (self):
                    return "<class X>"
            
            class HTMLDecorator(object):
                def __init__ (self, wrapped):
                    self.__wrapped = wrapped
            
                def html (self):
                    sep = cgi.escape (repr (self.__wrapped))
                    return sep.join (("<H1>", "</H1>"))
            
            inst_x=ClassX()
            inst_b=True
            
            print HTMLDecorator(inst_x).html()
            print HTMLDecorator(inst_b).html()
            

            【讨论】:

              【解决方案6】:

              @约翰(37479):

              非常接近,但后来我失去了 ClassX 的一切。下面是一位同事给我的东西,它确实可以解决问题,但它很可怕。必须有更好的方法。

              import cgi
              from math import sqrt
              
              class ClassX(object): 
                def __repr__(self): 
                  return "Best Guess"
              
              class ClassY(object):
                pass # ... with own __repr__
              
              inst_x=ClassX()
              
              inst_y=ClassY()
              
              inst_z=[ i*i for i in range(25) ]
              
              inst_b=True
              
              avoid="__class__ __init__ __dict__ __weakref__"
              
              class HTMLDecorator(object):
                  def __init__(self,master):
                      self.master = master
                      for attr in dir(self.master):
                          if ( not attr.startswith("__") or 
                              attr not in avoid.split() and "attr" not in attr):
                              self.__setattr__(attr, self.master.__getattribute__(attr))
              
                  def html(self): # an "enhanced" version of __repr__
                      return cgi.escape(self.__repr__()).join(("<H1>","</H1>"))
              
                  def length(self):
                      return sqrt(sum(self.__iter__()))
              
              print HTMLDecorator(inst_x).html()
              print HTMLDecorator(inst_y).html()
              wrapped_z = HTMLDecorator(inst_z)
              print wrapped_z.length()
              inst_z[0] += 70
              #wrapped_z[0] += 71
              wrapped_z.__setitem__(0,wrapped_z.__getitem__(0)+ 71)
              print wrapped_z.html()
              print HTMLDecorator(inst_b).html()
              

              输出:

              最佳猜测

              <__main__.classy>

              70.0

              [141, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576]

              正确

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-01-05
                相关资源
                最近更新 更多