Bind an instance of a base to a subclass - can this be done?

Discussion in 'Python' started by Lou Pecora, May 24, 2006.

  1. Lou Pecora

    Lou Pecora Guest

    I've been scanning Python in a Nutshell, but this seems to be either
    undoable or so subtle that I don't know how to do it.

    I want to subclass a base class that is returned from a Standard Library
    function (particularly, subclass file which is returned from open). I
    would add some extra functionality and keep the base functions, too.
    But I am stuck.

    E.g.

    class myfile(file):
    def myreadline():
    #code here to return something read from file

    Then do something like (I know this isn't right, I'm just trying to
    convey the idea of what I would like)

    mf=myfile()

    mf=open("Afile","r")

    s=mf.myreadline() # Use my added function

    mf.close() # Use the original file function


    Possible in some way? Thanks in advance for any clues.

    -- Lou Pecora (my views are my own) REMOVE THIS to email me.
    Lou Pecora, May 24, 2006
    #1
    1. Advertising

  2. Lou Pecora schrieb:
    > I've been scanning Python in a Nutshell, but this seems to be either
    > undoable or so subtle that I don't know how to do it.
    >
    > I want to subclass a base class that is returned from a Standard Library
    > function (particularly, subclass file which is returned from open). I
    > would add some extra functionality and keep the base functions, too.
    > But I am stuck.
    >
    > E.g.
    >
    > class myfile(file):
    > def myreadline():
    > #code here to return something read from file
    >
    > Then do something like (I know this isn't right, I'm just trying to
    > convey the idea of what I would like)
    >
    > mf=myfile()
    >
    > mf=open("Afile","r")
    >
    > s=mf.myreadline() # Use my added function
    >
    > mf.close() # Use the original file function
    >
    >
    > Possible in some way? Thanks in advance for any clues.


    Nope, not in that way. But you might consider writing a proxy/wrapper
    for an object. That looks like this (rouch sketch from head):

    class FileWrapper(object):
    def __init__(self, f):
    self._f = f

    def __getattr__(self, name):
    return getattr(self._f, name)

    def myreadline(self):
    ....


    Then you do

    f = FileWrapper(open(name, mode))


    Diez
    Diez B. Roggisch, May 24, 2006
    #2
    1. Advertising

  3. Le Mercredi 24 Mai 2006 22:04, Diez B. Roggisch a écrit :
    > Nope, not in that way. But you might consider writing a proxy/wrapper
    > for an object. That looks like this (rouch sketch from head):
    >
    > class FileWrapper(object):
    >     def __init__(self, f):
    >        self._f = f
    >
    >     def __getattr__(self, name):
    >        return getattr(self._f, name)
    >
    >     def myreadline(self):
    >        ....

    Why use a proxy when you can just inherit from the builtin file object ?

    class myFile(file) :
    def myreadline(self) : print 'yo'


    In [20]: myFile('frwiki-20060511-abstract.xml')
    Out[20]: <open file 'frwiki-20060511-abstract.xml', mode 'r' at 0xa78cc1e4>

    In [21]: myFile('frwiki-20060511-abstract.xml').myreadline()
    yo

    In [22]:



    --
    _____________

    Maric Michaud
    _____________

    Aristote - www.aristote.info
    3 place des tapis
    69004 Lyon
    Tel: +33 426 880 097
    Maric Michaud, May 24, 2006
    #3
  4. Lou Pecora wrote:
    > I want to subclass a base class that is returned from a Standard Library
    > function (particularly, subclass file which is returned from open). I
    > would add some extra functionality and keep the base functions, too.
    > But I am stuck.
    >
    > E.g.
    >
    > class myfile(file):
    > def myreadline():
    > #code here to return something read from file
    >
    > Then do something like (I know this isn't right, I'm just trying to
    > convey the idea of what I would like)
    >
    > mf=myfile()
    >
    > mf=open("Afile","r")
    >
    > s=mf.myreadline() # Use my added function
    >
    > mf.close() # Use the original file function
    >
    >
    > Possible in some way? Thanks in advance for any clues.


    This:

    >>> mf=myfile()
    >>> mf=open("Afile","r")


    Is actually creating an instance of myfile, then throwing it away,
    replacing it with an instance of file. There are no variable type
    declarations in Python.

    To accomplish what you want, simply instantiate the subclass:

    >>> mf=myfile("Afile","r")


    You don't need to do anything tricky, like binding the instance of the
    base class to a subclass. Python does actually support that, e.g.:

    >>> class Base(object):

    def f(self):
    return 'base'
    >>> class Subclass(Base):

    def f(self):
    return 'subclass'
    >>> b = Base()
    >>> b.__class__

    <class '__main__.Base'>
    >>> b.f()

    'base'
    >>> b.__class__ = Subclass
    >>> b.__class__

    <class '__main__.Subclass'>
    >>> b.f()

    'subclass'

    But the above won't work for the built-in file type:

    >>> f = file('foo')
    >>> f.__class__

    <type 'file'>
    >>> f.__class__ = Subclass

    TypeError: __class__ assignment: only for heap types

    Again though, just instantiate the subclass. Much cleaner.

    Or if that's not an option due to the way your module will be used,
    just define your custom file methods as global functions that take a
    file instance as a parameter. Python doesn't force you to use OOP for
    everything.

    --Ben
    Ben Cartwright, May 25, 2006
    #4
  5. Maric Michaud schrieb:
    > Le Mercredi 24 Mai 2006 22:04, Diez B. Roggisch a écrit :
    >> Nope, not in that way. But you might consider writing a proxy/wrapper
    >> for an object. That looks like this (rouch sketch from head):
    >>
    >> class FileWrapper(object):
    >> def __init__(self, f):
    >> self._f = f
    >>
    >> def __getattr__(self, name):
    >> return getattr(self._f, name)
    >>
    >> def myreadline(self):
    >> ....

    > Why use a proxy when you can just inherit from the builtin file object ?


    To be honest - in my perception file is a function. Which it isn't, but
    I see it that way :)

    You are of course right, and have the better solution (unless the OP is
    not in control of file creation).

    Diez
    Diez B. Roggisch, May 25, 2006
    #5
  6. Le Jeudi 25 Mai 2006 01:10, vous avez écrit :
    > The ratio of two durations has no meaning???

    Oh, sorry, sure it has, I wanted to say "it has no meaning in timedelta
    provided arithmetic".
    It's a ratio (no dimension) not a duration. In that sense the expected result
    should be a float, and the proposed operator will break the timedelta's
    arithmetic consistence.

    t, u, v <- timedeltas
    t+u # valid
    t / u # valid
    t / u + v # invalid while all terms are valids

    It's a big design flaw and I think it's the full answer to the original
    question.

    Le Jeudi 25 Mai 2006 02:26, Robert Kern a écrit :
    > > what you want is :
    > >
    > > num_weeks = time_diff.days / 7
    > > or
    > > num_weeks = (time_diff / 7).days

    >
    > Uh, no. Besides the integer division problem in your first line, keep in
    > mind that the .days attribute does not give you the time interval measured
    > in days. It gives you the number of *whole* days in the interval. The first
    > method will be incorrect if time_diff is not an even multiple of 1 day.
    > The latter will be incorrect if time_diff is not an even multiple of 7 days.

    In fact i was computing the exact number of whole weeks in the delta. In
    respect of that both expression are perfectly correct, but the second one
    isn't clear IMO (why this "days" attribute should give me the number of
    weeks ?).

    This said it's not hard to figure out the correct expression of the decimal
    value of weeks in deltas (discarding the microseconds which are not
    relevant) :
    num_weeks = (time_diff.days * 24* 3600 + time_diff.seconds) / (7.*24*3600)

    If I need to do much of these in a piece of code I would probably define some
    helper functions like this :

    def tomicroseconds(td) :
    return td.days * 24* 3600 * 10**6 +
    td.seconds * 10 ** 6 + td.microseconds

    def toseconds(td) : return float(tomicroseonds(td)) / 10 ** 6
    tominute, tohours, todays, toweeks, etc...

    and use float and int / and % operators.
    This is an easy and clean implementation IMHO.

    --
    _____________

    Maric Michaud
    _____________

    Aristote - www.aristote.info
    3 place des tapis
    69004 Lyon
    Tel: +33 426 880 097
    Maric Michaud, May 25, 2006
    #6
  7. Lou Pecora

    Lou Pecora Guest

    In article <>,
    "Diez B. Roggisch" <> wrote:

    > Lou Pecora schrieb:

    [cut]
    > >
    > > Then do something like (I know this isn't right, I'm just trying to
    > > convey the idea of what I would like)
    > >
    > > mf=myfile()
    > >
    > > mf=open("Afile","r")
    > > Possible in some way? Thanks in advance for any clues.

    >
    > Nope, not in that way. But you might consider writing a proxy/wrapper
    > for an object. That looks like this (rouch sketch from head):
    >
    > class FileWrapper(object):
    > def __init__(self, f):
    > self._f = f
    >
    > def __getattr__(self, name):
    > return getattr(self._f, name)
    >
    > def myreadline(self):
    > ....
    >
    > Then you do
    >
    > f = FileWrapper(open(name, mode))
    >
    > Diez


    Interesting. I have to think about this to understand if it is a
    solution I can use. But, thank you for a very different angle on this.

    -- Lou Pecora (my views are my own) REMOVE THIS to email me.
    Lou Pecora, May 25, 2006
    #7
  8. Lou Pecora

    Lou Pecora Guest

    In article <>,
    Maric Michaud <> wrote:

    > Le Mercredi 24 Mai 2006 22:04, Diez B. Roggisch a écrit :
    > > Nope, not in that way. But you might consider writing a proxy/wrapper
    > > for an object. That looks like this (rouch sketch from head):
    > >
    > > class FileWrapper(object):
    > >     def init (self, f):
    > >        self. f = f
    > >
    > >     def getattr (self, name):
    > >        return getattr(self. f, name)
    > >
    > >     def myreadline(self):
    > >        ....

    > Why use a proxy when you can just inherit from the builtin file object ?
    >
    > class myFile(file) :
    > def myreadline(self) : print 'yo'
    >
    >
    > In [20]: myFile('frwiki-20060511-abstract.xml')
    > Out[20]: <open file 'frwiki-20060511-abstract.xml', mode 'r' at 0xa78cc1e4>
    >
    > In [21]: myFile('frwiki-20060511-abstract.xml').myreadline()
    > yo
    >
    > In [22]:


    BINGO! This is exactly what I want. I didn't realize that I could open
    using file itself instead of open. I did find this in another section
    of Python in a Nutshell thanks to your suggestion.

    Thank you.

    And thanks to all who answered.

    -- Lou Pecora (my views are my own) REMOVE THIS to email me.
    Lou Pecora, May 25, 2006
    #8
  9. Lou Pecora

    Lou Pecora Guest

    I came up with this solution for subclassing the file object and making
    some easy I/O functions (much thanks to Maric Michaud for pointing me in
    the right direction). My goal was to make I/O of variables easy and in
    a form that I could easily visually examine the file (which I often need
    to do). The code also keeps it very clear as to what is being read in
    or out in a single function call.

    The class (inherited from file) in file ezfile.py:

    # ==== File subclass from file for EZ I/O =======================

    class ezfile(file):

    # ---- Write items to file ------------------
    # converts items list to string first using repr fcn.
    def printline(_, ls):
    sls=repr(ls)
    _.writelines(sls)

    # ---- Scan line from file & return items --------------------
    # converts scanned string to list first using eval fcn.
    def scanline(_,):
    sls=_.readline()
    return eval(sls)


    An example in a Python session:

    >>> from ezfile import *


    # Define some variables
    >>> x=2.334
    >>> i= 7
    >>> str='Some stuff here'


    # Open a file and output the variables to it
    >>> ff=ezfile('junk','w')
    >>> ff.printline([x,i,str])
    >>> ff.close()


    # Open the same file and read the values back in to other variables
    >>> f2=ezfile('junk','r')
    >>> y,j,thestr=f2.scanline()
    >>> print y,j,thestr

    2.334 7 Some stuff here
    >>> f2.close()
    >>>


    The file content looks like this:

    [2.3340000000000001, 7, 'Some stuff here']

    easy to see what is saved to the file.

    It works! Thanks, again. Comments welcome.

    -- Lou Pecora (my views are my own) REMOVE THIS to email me.
    Lou Pecora, May 25, 2006
    #9
    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. jstorta
    Replies:
    3
    Views:
    431
    jstorta
    Feb 20, 2006
  2. Gerry Sutton
    Replies:
    1
    Views:
    528
    Peter Otten
    Apr 16, 2005
  3. Sandra-24
    Replies:
    18
    Views:
    1,843
    Steve Holden
    Apr 29, 2006
  4. S.Volkov
    Replies:
    2
    Views:
    206
    S.Volkov
    Mar 12, 2006
  5. David Walker
    Replies:
    10
    Views:
    203
Loading...

Share This Page