簡體   English   中英

如何簡單地從現有實例繼承方法?

[英]How can I simply inherit methods from an existing instance?

下面我有一個非常簡單的例子來說明我正在嘗試做的事情。 我希望能夠將 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 (most recent call last):
  File "html.py", line 21, in 
    print HTMLDecorator(inst_x).html()
TypeError: default __new__ takes no parameters

我正在嘗試做的可能嗎? 如果是這樣,我做錯了什么?

非常接近,但隨后我失去了 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)

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 是在其他某個庫中定義的。

我正在嘗試做的可能嗎? 如果是這樣,我做錯了什么?

這當然是可能的。 問題是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

@約翰(37448):

抱歉,我可能用名字誤導了您(錯誤的選擇)。 我並不是真的在尋找裝飾器功能,或者根本沒有與裝飾器有關的東西。 我所追求的是讓 html(self) def 使用 ClassX 或 ClassY 的__repr__ 我希望它在不修改 ClassX 或 ClassY 的情況下工作。

啊,那樣的話,也許這樣的代碼會有用? 它實際上與裝飾器沒有任何關系,但演示了如何將參數傳遞給類的初始化函數並在以后檢索這些參數。

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()

@約翰(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()

輸出:

<H1>Best Guess</H1>
<H1><__main__.ClassY object at 0x891df0c></H1>
70.0
<H1>[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]</H1>
<H1>True</H1>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM