How to wrap a class's methods?

Discussion in 'Python' started by Grant Edwards, Feb 17, 2005.

  1. I want to subclass an IMAP connection so that most of the
    methods raise an exception if the returned status isn't 'OK'.
    This works, but there's got to be a way to do it that doesn't
    involve so much duplication:

    class MyImap4_ssl(imaplib.IMAP4_SSL):

    def login(*args):
    s,r = imaplib.IMAP4_SSL.login(*args)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def list(*args):
    s,r = imaplib.IMAP4_SSL.list(*args)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def search(*args):
    s,r = imaplib.IMAP4_SSL.search(*args)
    if s!='OK':
    raise NotOK((s,r))
    return r

    [and so on for another dozen methods]

    --
    Grant Edwards grante Yow! I OWN six pink
    at HIPPOS!!
    visi.com
    Grant Edwards, Feb 17, 2005
    #1
    1. Advertising

  2. Grant Edwards

    John Lenton Guest

    On Thu, Feb 17, 2005 at 07:32:55PM +0000, Grant Edwards wrote:
    > I want to subclass an IMAP connection so that most of the
    > methods raise an exception if the returned status isn't 'OK'.
    > This works, but there's got to be a way to do it that doesn't
    > involve so much duplication:
    >
    > class MyImap4_ssl(imaplib.IMAP4_SSL):
    >
    > def login(*args):
    > s,r = imaplib.IMAP4_SSL.login(*args)
    > if s!='OK':
    > raise NotOK((s,r))
    > return r
    >
    > def list(*args):
    > s,r = imaplib.IMAP4_SSL.list(*args)
    > if s!='OK':
    > raise NotOK((s,r))
    > return r
    >
    > def search(*args):
    > s,r = imaplib.IMAP4_SSL.search(*args)
    > if s!='OK':
    > raise NotOK((s,r))
    > return r
    >
    > [and so on for another dozen methods]
    >


    something like this:

    def NotOKVerified(orig):
    def f(*args):
    s, r = orig(*args)
    if s != 'OK':
    raise NotOK((s,r))
    return r
    return f

    class MyImap4_ssl(IMAP4_SSL):
    pass

    for method_name in ('login', 'list', 'search'):
    setattr(MyImap4_ssl, method_name, getattr(IMAP4_SSL, method_name))

    ?

    I'd usually put big fat warnings around this code, and explain exaclty
    why I need to do things this way...

    --
    John Lenton () -- Random fortune:
    "To vacillate or not to vacillate, that is the question ... or is it?"

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.4.0 (GNU/Linux)

    iD8DBQFCFPU3gPqu395ykGsRAmi/AJ9ETKZ6EZ5pgHfpibPOdPHbV24F0QCgltf4
    kDEAtn7POsO/tXW0s2uuMZM=
    =BjlO
    -----END PGP SIGNATURE-----
    John Lenton, Feb 17, 2005
    #2
    1. Advertising

  3. Grant Edwards wrote:
    > I want to subclass an IMAP connection so that most of the
    > methods raise an exception if the returned status isn't 'OK'.
    > This works, but there's got to be a way to do it that doesn't
    > involve so much duplication:
    >
    > class MyImap4_ssl(imaplib.IMAP4_SSL):
    >
    > def login(*args):
    > s,r = imaplib.IMAP4_SSL.login(*args)
    > if s!='OK':
    > raise NotOK((s,r))
    > return r
    >
    > def list(*args):
    > s,r = imaplib.IMAP4_SSL.list(*args)
    > if s!='OK':
    > raise NotOK((s,r))
    > return r
    >
    > def search(*args):
    > s,r = imaplib.IMAP4_SSL.search(*args)
    > if s!='OK':
    > raise NotOK((s,r))
    > return r
    >
    > [and so on for another dozen methods]


    You could try something like (Untested!):

    class Wrapper(object):
    def __init__(self, func):
    self.func = func
    def __call__(*args, **kwargs):
    self, args = args[0], args[1:]
    s, r = self.func(*args)
    if s != 'OK':
    raise NotOK((s, r))
    return r

    for func_name in ['login', 'list', 'search']:
    func = Wrapper(getattr(imaplib.IMAP4_SSL, func_name))
    setattr(imaplib.IMAP4_SSL, func_name, func)

    STeVe
    Steven Bethard, Feb 17, 2005
    #3
  4. Grant Edwards wrote:
    > I want to subclass an IMAP connection so that most of the
    > methods raise an exception if the returned status isn't 'OK'.
    > This works, but there's got to be a way to do it that doesn't
    > involve so much duplication:
    >
    > class MyImap4_ssl(imaplib.IMAP4_SSL):
    >
    > def login(*args):
    > s,r = imaplib.IMAP4_SSL.login(*args)
    > if s!='OK':
    > raise NotOK((s,r))
    > return r
    >
    > def list(*args):
    > s,r = imaplib.IMAP4_SSL.list(*args)
    > if s!='OK':
    > raise NotOK((s,r))
    > return r
    >
    > def search(*args):
    > s,r = imaplib.IMAP4_SSL.search(*args)
    > if s!='OK':
    > raise NotOK((s,r))
    > return r
    >
    > [and so on for another dozen methods]


    A more tested version of my other email:

    py> class C(object):
    .... def f(self, *args):
    .... print "f:", args
    .... def g(self, *args):
    .... print "g:", args
    ....
    py> class D(C):
    .... pass
    ....
    py> class Wrapper(object):
    .... def __init__(self, func):
    .... self.func = func
    .... def __call__(self, *args):
    .... print "wrapped"
    .... return self.func(*args)
    ....
    py> for name in ['f', 'g']:
    .... wrapper = Wrapper(getattr(C, name))
    .... setattr(D, name, new.instancemethod(wrapper, None, D))
    ....
    py> C().f()
    f: ()
    py> C().g(1)
    g: (1,)
    py> D().f()
    wrapped
    f: ()
    py> D().g(1)
    wrapped
    g: (1,)
    Steven Bethard, Feb 17, 2005
    #4
  5. On 2005-02-17, Steven Bethard <> wrote:

    > py> class C(object):
    > ... def f(self, *args):
    > ... print "f:", args
    > ... def g(self, *args):
    > ... print "g:", args
    > ...
    > py> class D(C):
    > ... pass
    > ...
    > py> class Wrapper(object):
    > ... def __init__(self, func):
    > ... self.func = func
    > ... def __call__(self, *args):
    > ... print "wrapped"
    > ... return self.func(*args)
    > ...
    > py> for name in ['f', 'g']:
    > ... wrapper = Wrapper(getattr(C, name))
    > ... setattr(D, name, new.instancemethod(wrapper, None, D))


    Thanks. The stuff provided by the "new" module is what I was
    missing.

    --
    Grant Edwards grante Yow! Wait... is this a FUN
    at THING or the END of LIFE in
    visi.com Petticoat Junction??
    Grant Edwards, Feb 17, 2005
    #5
  6. Grant Edwards wrote:

    > I want to subclass an IMAP connection so that most of the
    > methods raise an exception if the returned status isn't 'OK'.
    > This works, but there's got to be a way to do it that doesn't
    > involve so much duplication:
    >
    > class MyImap4_ssl(imaplib.IMAP4_SSL):
    >
    > def login(*args):
    > s,r = imaplib.IMAP4_SSL.login(*args)
    > if s!='OK':
    > raise NotOK((s,r))
    > return r
    >
    > def list(*args):
    > s,r = imaplib.IMAP4_SSL.list(*args)
    > if s!='OK':
    > raise NotOK((s,r))
    > return r
    >
    > def search(*args):
    > s,r = imaplib.IMAP4_SSL.search(*args)
    > if s!='OK':
    > raise NotOK((s,r))
    > return r
    >
    > [and so on for another dozen methods]


    How about using a delegator:

    class Wrapper:
    funcs = ("login", "list", "search")
    def __init__(self, classobj):
    self.__wrapped = classobj()
    def __getattr__(self, attr):
    if attr in Wrapper.funcs:
    def f(*args):
    f1 = getattr(self.__wrapped, attr)
    s,r = f1(args)
    if s != 'OK': raise NotOk((s,r))
    return r
    return f
    # raise some exception here
    imap = Wrapper(imaplib.IMAP4_SSL)

    If you wrap all methods you can ignore the if-test. Instead of the
    class object you can pass instances to the wrapper if you need
    special arguments for initialization.

    I don't like subclassing;)

    Mathias

    PS: note that we're wrapping the instance's methods, not the class's
    methods!
    Mathias Waack, Feb 17, 2005
    #6
  7. Grant Edwards

    Jeff Shannon Guest

    Steven Bethard wrote:

    > Grant Edwards wrote:
    >
    >> I want to subclass an IMAP connection so that most of the
    >> methods raise an exception if the returned status isn't 'OK'.
    >> This works, but there's got to be a way to do it that doesn't
    >> involve so much duplication:
    >>
    >> class MyImap4_ssl(imaplib.IMAP4_SSL):
    >>
    >> def login(*args):
    >> s,r = imaplib.IMAP4_SSL.login(*args)
    >> if s!='OK':
    >> raise NotOK((s,r))
    >> return r
    >> def list(*args):
    >> s,r = imaplib.IMAP4_SSL.list(*args)
    >> if s!='OK':
    >> raise NotOK((s,r))
    >> return r
    >> def search(*args):
    >> s,r = imaplib.IMAP4_SSL.search(*args)
    >> if s!='OK':
    >> raise NotOK((s,r))
    >> return r
    >> [and so on for another dozen methods]

    >
    >
    > You could try something like (Untested!):
    >
    > class Wrapper(object):
    > def __init__(self, func):
    > self.func = func
    > def __call__(*args, **kwargs):
    > self, args = args[0], args[1:]
    > s, r = self.func(*args)
    > if s != 'OK':
    > raise NotOK((s, r))
    > return r
    >
    > for func_name in ['login', 'list', 'search']:
    > func = Wrapper(getattr(imaplib.IMAP4_SSL, func_name))
    > setattr(imaplib.IMAP4_SSL, func_name, func)


    You could probably also do this as a factory function, rather than as
    a class (also untested!):

    def Wrapper(func):
    def wrapped(self, *args, **kwargs):
    s, r = func(self, *args, **kwargs)
    if s != 'OK':
    raise NotOK((s,r))
    return r
    return wrapped

    I believe that this will be semantically almost equivalent, but
    conceptually slightly simpler.

    Jeff Shannon
    Jeff Shannon, Feb 17, 2005
    #7
  8. Grant Edwards wrote:
    > On 2005-02-17, Steven Bethard <> wrote:
    >
    >
    >>py> class C(object):
    >>... def f(self, *args):
    >>... print "f:", args
    >>... def g(self, *args):
    >>... print "g:", args
    >>...
    >>py> class D(C):
    >>... pass
    >>...
    >>py> class Wrapper(object):
    >>... def __init__(self, func):
    >>... self.func = func
    >>... def __call__(self, *args):
    >>... print "wrapped"
    >>... return self.func(*args)
    >>...
    >>py> for name in ['f', 'g']:
    >>... wrapper = Wrapper(getattr(C, name))
    >>... setattr(D, name, new.instancemethod(wrapper, None, D))

    >
    >
    > Thanks. The stuff provided by the "new" module is what I was
    > missing.
    >

    No magic in the 'new' module - new.instancemethod is just a synonym for the
    method type:

    >>> import new, types
    >>> new.instancemethod is types.MethodType

    True

    Michael
    Michael Spencer, Feb 17, 2005
    #8
  9. On 2005-02-17, Mathias Waack <> wrote:

    > How about using a delegator:
    >
    > class Wrapper:
    > funcs = ("login", "list", "search")
    > def __init__(self, classobj):
    > self.__wrapped = classobj()
    > def __getattr__(self, attr):
    > if attr in Wrapper.funcs:
    > def f(*args):
    > f1 = getattr(self.__wrapped, attr)
    > s,r = f1(args)
    > if s != 'OK': raise NotOk((s,r))
    > return r
    > return f
    > # raise some exception here
    > imap = Wrapper(imaplib.IMAP4_SSL)
    >
    > If you wrap all methods you can ignore the if-test.


    I'm not, and the other methods should behave "normally":

    class Wrapper:
    funcs = ("login", "list", "search")
    def __init__(self, classobj):
    self.__wrapped = classobj()
    def __getattr__(self, attr):
    if attr in Wrapper.funcs:
    def f(*args):
    f1 = getattr(self.__wrapped, attr)
    s,r = f1(args)
    if s != 'OK': raise NotOk((s,r))
    return r
    else:
    f = getattr(self.__wrapped, attr)
    return f

    > PS: note that we're wrapping the instance's methods, not the class's
    > methods!


    You're right.

    --
    Grant Edwards grante Yow! "THE LITTLE PINK
    at FLESH SISTERS," I saw them
    visi.com at th' FLUROESCENT BULB
    MAKERS CONVENTION...
    Grant Edwards, Feb 17, 2005
    #9
  10. On 2005-02-17, Michael Spencer <> wrote:

    >> Thanks. The stuff provided by the "new" module is what I was
    >> missing.

    >
    > No magic in the 'new' module - new.instancemethod is just a synonym for the
    > method type:
    >
    > >>> import new, types
    > >>> new.instancemethod is types.MethodType

    > True


    Thanks -- I didn't know that either.

    --
    Grant Edwards grante Yow! I joined scientology
    at at a garage sale!!
    visi.com
    Grant Edwards, Feb 17, 2005
    #10
  11. Michael Spencer wrote:
    > Grant Edwards wrote:
    >>
    >> Thanks. The stuff provided by the "new" module is what I was
    >> missing.
    >>

    > No magic in the 'new' module - new.instancemethod is just a synonym for
    > the method type:
    >
    > >>> import new, types
    > >>> new.instancemethod is types.MethodType

    > True


    (Assuming you're using Python 2.3 or newer)
    Dave Benjamin, Feb 17, 2005
    #11
  12. John Lenton wrote:
    > On Thu, Feb 17, 2005 at 07:32:55PM +0000, Grant Edwards wrote:



    >
    > I'd usually put big fat warnings around this code, and explain exaclty
    > why I need to do things this way...
    >
    >


    As a low-tech alternative, what about sourcecode generation, since you are
    targetting a python module? This gives two advantages vs the wrapping function:
    1) the magic all occurs at coding time 2) the method signatures are documented.

    Michael

    import imaplib
    import inspect
    import types
    instancemethod = types.MethodType

    # The function template
    funcwrapper = \
    """
    def %(name)s%(argspec)s:
    s,r = imaplib.IMAP4_SSL.%(name)s%(callspec)s
    if s!='OK':
    raise NotOK((s,r))
    return r"""

    # A helper function to get the template parameters
    def getargs(method):
    argspec = inspect.getargspec(method)
    callspec = tuple(argspec[:3] + (None,))# No default

    return {"name": method.__name__,
    "argspec": inspect.formatargspec(*argspec),
    "callspec": inspect.formatargspec(*callspec)}

    # Do the stuff manually:
    >>> obj = imaplib.IMAP4_SSL
    >>> attrnames = [meth for meth in dir(imaplib.IMAP4_SSL) if not

    meth.startswith("_")]
    >>> attributes = [getattr(obj, attrname) for attrname in attrnames]
    >>> methods = [attribute for attribute in attributes if

    inspect.ismethod(attribute)]
    >>> print "\n".join(funcwrapper % getargs(method) for method in methods)


    def append(self, mailbox, flags, date_time, message):
    s,r = imaplib.IMAP4_SSL.append(self, mailbox, flags, date_time, message)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def authenticate(self, mechanism, authobject):
    s,r = imaplib.IMAP4_SSL.authenticate(self, mechanism, authobject)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def check(self):
    s,r = imaplib.IMAP4_SSL.check(self)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def close(self):
    s,r = imaplib.IMAP4_SSL.close(self)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def copy(self, message_set, new_mailbox):
    s,r = imaplib.IMAP4_SSL.copy(self, message_set, new_mailbox)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def create(self, mailbox):
    s,r = imaplib.IMAP4_SSL.create(self, mailbox)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def delete(self, mailbox):
    s,r = imaplib.IMAP4_SSL.delete(self, mailbox)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def deleteacl(self, mailbox, who):
    s,r = imaplib.IMAP4_SSL.deleteacl(self, mailbox, who)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def expunge(self):
    s,r = imaplib.IMAP4_SSL.expunge(self)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def fetch(self, message_set, message_parts):
    s,r = imaplib.IMAP4_SSL.fetch(self, message_set, message_parts)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def getacl(self, mailbox):
    s,r = imaplib.IMAP4_SSL.getacl(self, mailbox)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def getquota(self, root):
    s,r = imaplib.IMAP4_SSL.getquota(self, root)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def getquotaroot(self, mailbox):
    s,r = imaplib.IMAP4_SSL.getquotaroot(self, mailbox)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def list(self, directory='""', pattern='*'):
    s,r = imaplib.IMAP4_SSL.list(self, directory, pattern)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def login(self, user, password):
    s,r = imaplib.IMAP4_SSL.login(self, user, password)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def login_cram_md5(self, user, password):
    s,r = imaplib.IMAP4_SSL.login_cram_md5(self, user, password)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def logout(self):
    s,r = imaplib.IMAP4_SSL.logout(self)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def lsub(self, directory='""', pattern='*'):
    s,r = imaplib.IMAP4_SSL.lsub(self, directory, pattern)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def myrights(self, mailbox):
    s,r = imaplib.IMAP4_SSL.myrights(self, mailbox)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def namespace(self):
    s,r = imaplib.IMAP4_SSL.namespace(self)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def noop(self):
    s,r = imaplib.IMAP4_SSL.noop(self)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def open(self, host='', port=993):
    s,r = imaplib.IMAP4_SSL.open(self, host, port)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def partial(self, message_num, message_part, start, length):
    s,r = imaplib.IMAP4_SSL.partial(self, message_num, message_part, start,
    length)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def print_log(self):
    s,r = imaplib.IMAP4_SSL.print_log(self)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def proxyauth(self, user):
    s,r = imaplib.IMAP4_SSL.proxyauth(self, user)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def read(self, size):
    s,r = imaplib.IMAP4_SSL.read(self, size)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def readline(self):
    s,r = imaplib.IMAP4_SSL.readline(self)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def recent(self):
    s,r = imaplib.IMAP4_SSL.recent(self)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def rename(self, oldmailbox, newmailbox):
    s,r = imaplib.IMAP4_SSL.rename(self, oldmailbox, newmailbox)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def response(self, code):
    s,r = imaplib.IMAP4_SSL.response(self, code)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def search(self, charset, *criteria):
    s,r = imaplib.IMAP4_SSL.search(self, charset, *criteria)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def select(self, mailbox='INBOX', readonly=None):
    s,r = imaplib.IMAP4_SSL.select(self, mailbox, readonly)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def send(self, data):
    s,r = imaplib.IMAP4_SSL.send(self, data)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def setacl(self, mailbox, who, what):
    s,r = imaplib.IMAP4_SSL.setacl(self, mailbox, who, what)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def setquota(self, root, limits):
    s,r = imaplib.IMAP4_SSL.setquota(self, root, limits)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def shutdown(self):
    s,r = imaplib.IMAP4_SSL.shutdown(self)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def socket(self):
    s,r = imaplib.IMAP4_SSL.socket(self)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def sort(self, sort_criteria, charset, *search_criteria):
    s,r = imaplib.IMAP4_SSL.sort(self, sort_criteria, charset,
    *search_criteria)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def ssl(self):
    s,r = imaplib.IMAP4_SSL.ssl(self)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def status(self, mailbox, names):
    s,r = imaplib.IMAP4_SSL.status(self, mailbox, names)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def store(self, message_set, command, flags):
    s,r = imaplib.IMAP4_SSL.store(self, message_set, command, flags)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def subscribe(self, mailbox):
    s,r = imaplib.IMAP4_SSL.subscribe(self, mailbox)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def thread(self, threading_algorithm, charset, *search_criteria):
    s,r = imaplib.IMAP4_SSL.thread(self, threading_algorithm, charset,
    *search_criteria)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def uid(self, command, *args):
    s,r = imaplib.IMAP4_SSL.uid(self, command, *args)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def unsubscribe(self, mailbox):
    s,r = imaplib.IMAP4_SSL.unsubscribe(self, mailbox)
    if s!='OK':
    raise NotOK((s,r))
    return r

    def xatom(self, name, *args):
    s,r = imaplib.IMAP4_SSL.xatom(self, name, *args)
    if s!='OK':
    raise NotOK((s,r))
    return r
    >>>
    Michael Spencer, Feb 17, 2005
    #12
  13. On 2005-02-17, Michael Spencer <> wrote:
    >> I'd usually put big fat warnings around this code, and explain exaclty
    >> why I need to do things this way...

    >
    > As a low-tech alternative, what about sourcecode generation,


    Interesting idea. It's almost like haveing a macro capability. :)

    --
    Grant Edwards grante Yow! Oh my GOD -- the
    at SUN just fell into YANKEE
    visi.com STADIUM!!
    Grant Edwards, Feb 17, 2005
    #13
  14. Grant Edwards

    rbt Guest

    Jeff Shannon wrote:
    > You could probably also do this as a factory function, rather than as a
    > class (also untested!):
    >
    > def Wrapper(func):
    > def wrapped(self, *args, **kwargs):
    > s, r = func(self, *args, **kwargs)
    > if s != 'OK':
    > raise NotOK((s,r))
    > return r
    > return wrapped
    >
    > I believe that this will be semantically almost equivalent, but
    > conceptually slightly simpler.
    >
    > Jeff Shannon


    This is a nice example. I have used sub-functions (functions within
    functions) recently with some code, but I've wondered how proper it is
    to do this. Is this type of thing frowned upon?
    rbt, Feb 20, 2005
    #14
  15. rbt wrote:
    > Jeff Shannon wrote:
    >
    >> You could probably also do this as a factory function, rather than as
    >> a class (also untested!):
    >>
    >> def Wrapper(func):
    >> def wrapped(self, *args, **kwargs):
    >> s, r = func(self, *args, **kwargs)
    >> if s != 'OK':
    >> raise NotOK((s,r))
    >> return r
    >> return wrapped
    >>
    >> I believe that this will be semantically almost equivalent, but
    >> conceptually slightly simpler.
    >>
    >> Jeff Shannon

    >
    > This is a nice example. I have used sub-functions (functions within
    > functions) recently with some code, but I've wondered how proper it is
    > to do this. Is this type of thing frowned upon?


    Nope. If it was frowned upon, Python wouldn't support it. ;) Sometimes
    it's even faster:

    -------------------- test.py --------------------
    def wrapper(func):
    def wrapped(*args, **kwargs):
    return bool(func(*args, **kwargs))
    return wrapped

    class Wrapper(object):
    def __init__(self, func):
    self.func = func
    def __call__(self, *args, **kwargs):
    return bool(self.func(*args, **kwargs))
    -------------------------------------------------

    $ python -m timeit -s "import test; w = test.wrapper(sum)" "w([]); w([1,2])"
    100000 loops, best of 3: 4.77 usec per loop

    $ python -m timeit -s "import test; w = test.Wrapper(sum)" "w([]); w([1,2])"
    100000 loops, best of 3: 6.52 usec per loop

    Personally, I still tend towards the class-based version, but I'm sure
    in many cases the nested function version would work just as well.

    STeVe
    Steven Bethard, Feb 20, 2005
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Aaron Fude

    To wrap or not to wrap?

    Aaron Fude, May 8, 2008, in forum: Java
    Replies:
    12
    Views:
    674
    Chronic Philharmonic
    May 10, 2008
  2. Oltmans
    Replies:
    6
    Views:
    319
    Terry Reedy
    Mar 11, 2009
  3. Kenneth McDonald
    Replies:
    5
    Views:
    289
    Kenneth McDonald
    Sep 26, 2008
  4. Art Werschulz

    Text::Wrap::wrap difference

    Art Werschulz, Sep 22, 2003, in forum: Perl Misc
    Replies:
    0
    Views:
    208
    Art Werschulz
    Sep 22, 2003
  5. Art Werschulz

    Text::Wrap::wrap difference

    Art Werschulz, Sep 24, 2003, in forum: Perl Misc
    Replies:
    1
    Views:
    226
    Anno Siegel
    Sep 25, 2003
Loading...

Share This Page