By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,594 Members | 3,459 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,594 IT Pros & Developers. It's quick & easy.

Seems like I want a pre-processor, but...

P: n/a
After some digging it seems that python does not have any equivalent to
C's #if directives, and I don't get it...

For example, I've got a bit of python 2.3 code that uses
collections.deque.pop(0) in order to pop the leftmost item. In python
2.4 this is no longer valid - there is no argument on pop (rightmost
only now) and you call .popleft() instead.

I would like my code to work in both versions for now and simply want
to add code like:

if sys.version[:3] == "2.3":
return self.myDeque.pop(0)
else:
return self.myDeque.popleft()

but am recoiling a bit at the unnecessary conditional in there that I
think will be run on every execution - unless the compiler has some
magic detection of things like sys.version to compile out the
conditional as if it were a preprocessor directive (seems highly
unlikely!)?.

What is the pythonic thing to do? This is in a generally usable file,
not a package, so I don't want to make a version for each (which seems
to be what every package out there does). It seems to be begging for a
pre-processor directive set.

Thanks,
Russ

Mar 28 '06 #1
Share this Question
Share on Google+
9 Replies


P: n/a
Russell Warren wrote:
For example, I've got a bit of python 2.3 code that uses
collections.deque.pop(0) in order to pop the leftmost item. In python
2.4 this is no longer valid - there is no argument on pop (rightmost
only now) and you call .popleft() instead.
the collections module was added in 2.4, so it's not clear what code you're
really using under 2.3. but since it's not a standard module, maybe you could
add the missing method yourself ?
I would like my code to work in both versions for now and simply want
to add code like:

if sys.version[:3] == "2.3":
return self.myDeque.pop(0)
else:
return self.myDeque.popleft()

but am recoiling a bit at the unnecessary conditional in there that I
think will be run on every execution - unless the compiler has some
magic detection of things like sys.version to compile out the
conditional as if it were a preprocessor directive (seems highly
unlikely!)?.

What is the pythonic thing to do?


fork the function/method:

if sys.version_info < (2, 4):
def myfunc(self):
# using deque emulation
return self.myDeque.pop(0)
else:
def myfunc(self):
return self.myDeque.popleft()

or wrap the non-standard deque class in a compatibility wrapper:

if sys.version_info < (2, 4):
class mydequeclass(deque):
def popleft(self):
return self.pop(0)

...

return self.myDeque.popleft()

</F>

Mar 28 '06 #2

P: n/a
Russell Warren wrote:
After some digging it seems that python does not have any equivalent to
C's #if directives, and I don't get it...

For example, I've got a bit of python 2.3 code that uses
collections.deque.pop(0) in order to pop the leftmost item. In python
2.4 this is no longer valid - there is no argument on pop (rightmost
only now) and you call .popleft() instead.

I would like my code to work in both versions for now and simply want
to add code like:

if sys.version[:3] == "2.3":
return self.myDeque.pop(0)
else:
return self.myDeque.popleft()


Often you can make these tests one-time by defining an appropriate
object whose value depends on the test, then using that object instead
of repeatedly making the test. In this case, I assume the code above is
inside a class method. You could have the class conditionally define a
myPopLeft() method like this (not tested):

class MyClass(object):
...
if sys.version[:3] == "2.3":
def myPopLeft(self):
return self.myDeque.pop(0)
else:
def myPopLeft(self):
return self.myDeque.popleft()

Now the class has a myPopLeft() method that does the right thing, and
sys.version is only tested once, at class declaration time.

You might want to make the condition explicitly on the deque class,
also, using has_attr(deque, 'popleft').

Another example is the common code used to define 'set' portably across
Python 2.3 and 2.4:

try:
set
except NameError:
from sets import Set as set
In general the idea is to move the test from 'every time I need to do
something' to 'once when some name is defined'.

Kent

Mar 28 '06 #3

P: n/a
Russell Warren wrote:
After some digging it seems that python does not have any equivalent to
C's #if directives, and I don't get it...

For example, I've got a bit of python 2.3 code that uses
collections.deque.pop(0) in order to pop the leftmost item. In python
2.4 this is no longer valid - there is no argument on pop (rightmost
only now) and you call .popleft() instead.
collections is new in 2.4 -- I assume you mean list.pop(0) versus
collections.deque.popleft().
I would like my code to work in both versions for now and simply want
to add code like:

if sys.version[:3] == "2.3":
return self.myDeque.pop(0)
else:
return self.myDeque.popleft()

but am recoiling a bit at the unnecessary conditional in there that I
think will be run on every execution - unless the compiler has some
magic detection of things like sys.version to compile out the
conditional as if it were a preprocessor directive (seems highly
unlikely!)?.

What is the pythonic thing to do? This is in a generally usable file,
not a package, so I don't want to make a version for each (which seems
to be what every package out there does). It seems to be begging for a
pre-processor directive set.


Here's how I would rewrite your example:

try:
from collections import deque
except ImportError:
class deque(list):
def popleft(self):
return self.pop(0)

# in your method:
return self.myDeque.popleft()

That way the performance impact almost vanishes for the newer python and
your code is less cluttered with if ... else statements that are only there
to pick the version specific code.

Peter
Mar 28 '06 #4

P: n/a
> the collections module was added in 2.4

Ah... sorry about that. I should have checked my example more closely.
What I'm actually doing is rebinding some Queue.Queue behaviour in a
"safe" location like this:

def _get(self):
ret = self.queue.popleft()
DoSomethingSimple()
return ret

And self.queue.popleft() used to be self.queue.pop(0). self.queue is a
deque object in 2.4 so I just used transferred that unluckily to the
post in a poor attempt to simplify it - I had no clue that it was new.
Should have made one up from scratch.

Anyway - it worked... you've answered my question perfectly, thanks. I
hadn't considered that the module loading phase could basically used
for preprocessing. You even helped by subtly providing a better
version checker... I didn't even know you could use < with a tuple like
that. I'll have to look into the logic rules there.

Russ

Mar 28 '06 #5

P: n/a
Thanks guys - all great responses that answered my question in a few
different ways with the addition of some other useful tidbits!

This is a nice summary:
In general the idea is to move the test from 'every time I need to do
something' to 'once when some name is defined'.


Gotta love the response time of this newsgroup...

Russ

Mar 28 '06 #6

P: n/a

Russell Warren wrote:
the collections module was added in 2.4


Ah... sorry about that. I should have checked my example more closely.
What I'm actually doing is rebinding some Queue.Queue behaviour in a
"safe" location like this:

def _get(self):
ret = self.queue.popleft()
DoSomethingSimple()
return ret


What you should have done is call the base class's _get method, like
this:

def _get(self):
ret = Queue._get(self)
DoSomethingSimple()
return ret

This'll work in 2.3, 2.4, and if they were to change the type of the
queue again in 2.5, it would still work without any changes. Don't
redo the work the base class does if you don't have to.
Carl Banks

Mar 29 '06 #7

P: n/a
In article <11**********************@v46g2000cwv.googlegroups .com>,
Russell Warren <ru************@gmail.com> wrote:
Mar 29 '06 #8

P: n/a
Yes, I definitely should have done that for that case. I'm not
entirely sure why I didn't. If I had, though, I may not have been
prompted to ask the question and get all the other great little
tidbits!

Mar 30 '06 #9

P: n/a
Well, Bill Mill and I simultaneously and independently decided to write
a preprocessor to strip out the unfortunate "@" decorator syntax. I
think we were both aiming at a polemic purpose rather than a practical
one, but as time fades it seems less clear what we were simultaneously
inspired to achieve. Each of us did a crude pass at it and then on
encountering each other's approach realized a truly satisfactory
implementation would probably be harder than it was worth...

In any case isn't ipython an instance of a useful preprocessor?

mt

Mar 30 '06 #10

This discussion thread is closed

Replies have been disabled for this discussion.