Accessing overridden __builtin__s?

G

garyjefferson123

I'm having a scoping problem. I have a module called SpecialFile,
which defines:

def open(fname, mode):
return SpecialFile(fname, mode)

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(). So,
if I do:

f = SpecialFile.open(name, mode)

I get infinite recursion.

How do I tell my class that I want to refer to the __builtin__ open(),
and not the one defined in the module?

Thanks,
Gary
 
S

Steven Bethard

I'm having a scoping problem. I have a module called SpecialFile,
which defines:

def open(fname, mode):
return SpecialFile(fname, mode)

class SpecialFile:

def __init__(self, fname, mode):
self.f = open(fname, mode)
...
[snip]

How do I tell my class that I want to refer to the __builtin__ open(),
and not the one defined in the module?

import __builtin__
....
self.f = __builtin__.open(fname, mode)
....

STeVe
 
B

bruno at modulix

I'm having a scoping problem. I have a module called SpecialFile,

The convention is to use all_lowercase names for modules, and CamelCase
for classes.
which defines:

def open(fname, mode):
return SpecialFile(fname, mode)

This shadows the builtin open() function.
class SpecialFile:

Old-style classes are deprecated, please use new-style classes
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(). So,
if I do:

f = SpecialFile.open(name, mode)

I get infinite recursion.

How do I tell my class that I want to refer to the __builtin__ open(),
and not the one defined in the module?

You can use Steven's solution, or keep a reference to the builtin open()
function before defining your own open() function:

builtin_open = open
def open(fname, mode):
return SpecialFile(fname, mode):

class SpecialFile(object):
def __init__(self, fname, mode):
self.f = builtin_open(fname, mode)
 
S

Steven D'Aprano

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.
 
F

Fredrik Lundh

Steven said:
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?

SpecialFile is a module. please read the posts you reply to, and please cut out
the "holier than thou" design advice.

overriding builtins is perfectly okay, if it makes sense for the target application.

just remember to use __builtin__ (a module) instead of __builtins__ (a cpython
implementation hack) if you need to access the original builtins.

</F>
 
B

bruno at modulix

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

Steven, it seems clear that the OP knows that already. Try reading the
previous sentence as:
"""
The problem, if it isn't obvioius, is that the open() call in __init__
no longer refers to the builtin's open(), but to the module's open().
"""

Does it make more sens ?-)
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().




I see you are already using an open method.

There again, you may want to read more carefully: SpecialFile is *also*
the module's name - which, I agree, is not pythonic.

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

Small variant, more builtins-open-like, and taking full advantage of
Python's delegation mechanism:

class SpecialFile(object):
def __init__(self, fname, mode='r'):
self.fname = fname
self.mode = mode
self._file = open(self.fname, self.mode)

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

which allows:

sf = SpecialFile("hello.txt")
# then use it just like any other file object

My 2 cents
 
F

Fredrik Lundh

bruno at modulix said:
There again, you may want to read more carefully: SpecialFile is *also*
the module's name - which, I agree, is not pythonic.

this approach was recommended by the official style until very recently.

http://www.python.org/doc/essays/styleguide.html

Modules that export a single class (or a number of closely related
classes, plus some additional support) are often named in Mixed-
Case, with the module name being the same as the class name
(e.g. the standard StringIO module).

</F>
 
D

Dennis Lee Bieber

In your code, open() is not a module, it is a function.
I think by "... module open" the meaning was "... the open IN the
module" (since the start of the discussion described it as part of a
normal user-written module).
--
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

portable multiprocessing code 0
Code sharing 2
Static method 7
python parser overridden by pymol 6
Trouble with code 2
Python battle game help 2
Weird Python behaviour 4
HTMLParser not parsing whole html file 4

Members online

Forum statistics

Threads
474,290
Messages
2,571,453
Members
48,129
Latest member
DianneCarn

Latest Threads

Top