기존 인스턴스에서 메서드를 간단하게 상속하려면 어떻게 해야 합니까?

StackOverflow https://stackoverflow.com/questions/37479

문제

아래에는 제가 하려는 작업에 대한 매우 간단한 예가 있습니다.다른 클래스와 함께 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()

하지만 주의하세요. 이와 같은 원숭이 패치는 코드의 가독성과 유지 관리 측면에서 높은 비용을 수반합니다.1년 후 이 코드로 돌아가면 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 ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top