AttributeError: 'module' object has no attribute 'fork'

Steven D'Aprano steve+comp.lang.python at pearwood.info
Fri Aug 8 01:48:17 EDT 2014


Rustom Mody wrote:

> On Thursday, August 7, 2014 10:26:56 PM UTC+5:30, Steven D'Aprano wrote:
>> Roy Smith wrote:
> 
>> >  Peter Otten  wrote:
>> >> os.fork()
>> >> Fork a child process.
>> >> ...
>> >> Availability: Unix.
>> >> """
>> >> You are using the wrong operating system ;)
>> > To be honest, this could be considered a buglet in the os module.  It
>> > really should raise:
>> > NotImplementedError("fork() is only available on unix")
>> > or perhaps even, as Peter suggests:
>> > NotImplementedError("You are using the wrong operating system")
>> > either of those would be better than AttributeError.
> 
>> I disagree. How would you tell if fork is implemented? With the current
>> behaviour, telling whether fork is implemented or not is simple:
> 
>> is_implemented = hasattr(os, "fork")
[...]
> Surely I am missing something but why not check os.fork before
> checking os.fork() ?

Yes, you're missing something. That's what hasattr does.

But with Roy's suggestion, testing for the existence of os.fork is not
sufficient, because it will exist even on platforms where fork doesn't
exist. So testing that os.fork exists is not sufficient to tell whether or
not you can actually fork.

Let's put it another way: code should, when possible, use feature detection
rather than version (or platform) detection:

# No, bad:
if os.name.startswith('linux'):
    pid = os.fork()
else:
    do_something_else()

That's harmful, because:

- perhaps there are other OSes apart from Linux which allow forking;
- maybe some day even Windows;
- and hypothetically there could even be a kind of Linux that doesn't
  allow forking.

Feature detection is much more reliable and future-proof:

if hasattr(os, 'fork'):
    # we don't care what OS, so long as it allows forking
    pid = os.fork()
else:
    do_something_else()


provided os.fork only exists when it does something. Roy's suggestion means
that os.fork will exist even when useless.

Now, many times you can avoid the Look Before You Leap test:

try:
    pid = os.fork()
except AttributeError:  # Or NotImplementedError, in Roy's suggestion.
    do_something_else()


and that's fine too. In this specific scenario, catching NotImplementedError
is no harder than catching AttributeError. But sometimes you want to know
up front whether you can fork later, without committing to forking right
now, and that's where Roy's suggestion becomes painful:

>> try:
>>     pid = os.fork()
>> except NotImplementedError:
>>     is_implemented = False
>> else:
>>     if pid == 0:
>>         # In the child process.
>>         os._exit(0)  # Unconditionally exit, right now, no excuses.
>>     is_implemented = True


Eight lines of tricky, potentially expensive code, versus a cheap hasattr
test.


> Something along these lines
> 
>>>> try:
> ...   os.fork
> ... except AttributeError:
> ...   ii = False
> ... else:
> ...   ii = True

That's just a much more verbose way of writing ii = hasattr(os, 'fork').



-- 
Steven




More information about the Python-list mailing list