Accessing overridden __builtin__s?

Steven D'Aprano steve at REMOVETHIScyber.com.au
Tue Mar 14 12:14:39 CET 2006


On Mon, 13 Mar 2006 21:28:06 -0800, garyjefferson123 wrote:

> I'm having a scoping problem.  I have a module called SpecialFile,
> which defines:
> 
> def open(fname, mode):
>   return SpecialFile(fname, mode)

This is called "shadowing a built-in", and generally speaking it causes
Bad Things To Happen. The secret to avoiding those Bad Things is to not
shadow built-ins. This isn't a hard and fast rule, but as a good general
principle, if you have to ask "How do I avoid this problem?", you
shouldn't be using shadowing.

(Think of it this way: if you have to ask "How do I avoid being horribly
injured when I crash my car into a wall at 90mph?", you shouldn't be
crashing your car into a wall at 90mph. Yes, I know that makes the
bootstrapping problem difficult for those budding stunt men and women who
want to learn, but they generally manage. And most of the time they manage
by not actually crashing their car into a wall at 90mph -- they find a
better way to get the same effect.)


> class SpecialFile:
> 
>   def __init__(self, fname, mode):
>     self.f = open(fname, mode)
>     ...
> 
> 
> The problem, if it isn't obvioius, is that the open() call in __init__
> no longer refers to the builtin open(), but to the module open().

In your code, open() is not a module, it is a function.

A better technique will be to turn open into a method of the class
SpecialFile, rather than a bare function. That way you keep open() the
built-in function separate from SpecialFile.open().

> So, if I do:
> 
> f = SpecialFile.open(name, mode)
> 
> I get infinite recursion.

I see you are already using an open method. So let me see if I have this
right: you have a function open, plus an open method? Why?

As near as I can tell, you have a function called "open" which returns a
SpecialFile instance. I don't understand why you would want to do that --
it seems like a poor API design to me. But maybe there's something I don't
understand. It looks like you are expecting to do this:

file = open('data.txt', 'r')
# file is now an automatically opened SpecialFile.

This is bad design because it isn't clear that you have done something
special. It *looks* like you have just opened an ordinary file, and unless
you study the entire module, you wouldn't have any clue that in fact you
have opened a SpecialFile instead.

I would handle it like this:

class SpecialFile(object):
    def __init__(self, fname, mode='r'):
        self.fname = fname
        self.mode = mode
    def open(self):
        self.f = open(self.fname, self.mode)
    def close(self):
        self.f.close()
    def read(self):
        return self.f.read()
    def write(self, data):
        self.f.write(data)

You use it like so:

sf = SpecialFile("hello.txt")
sf.open()
data = sf.read()
sf.close()

(Actually, I wouldn't handle it like this at all, unless a SpecialFile did
things that an ordinary file didn't. But presumably you have something
special in mind.)

This, in my opinion, is a better solution. You don't have to jump through
hoops to get back at the built-in version of open, and the code is
self-documenting: to open a SpecialFile, you ask for a SpecialFile. 



-- 
Steven.




More information about the Python-list mailing list