简体   繁体   中英

Supporting types in unified python 2/3 version

I've got some code written with python 2.7.x that I'm trying to make compatible with python 3.x. I've resolved most of the issues converting the code to work under both versions, but wanted advice dealing with int/long types.

Much of the work to unify int and long types occurred in much earlier (2.4.x) releases and the distinction was completely removed in V3 ( The '1L' format is no longer valid). At the same time the types module was modified to remove references to types already built-in and the redundant 'long' built-in type was removed.

So under V2.x I still need to support code like:

if type(var) == int or type(var) == long :
     do_stuff

or

if type(var) == int :
     do_int_stuff
elif type(var) == long :
     do_long_stuff

But with V3 there is no built-in class for long, and no need to do_long_stuff that's different from normal do_int_stuff. The built-in class type variable 'long' is no longer defined, so this code would fail with a NameError.

One easy solution is to define 'long' as None or some other nonsense type under v3, understanding type(var) != long for any var. The long built-in class type defined under v2.x would remain the same.

if sys.version_info.major == 3 :
     long = None

Is None the best value to use? In my case setting 'long = int' isn't what I want to use.

First of all, you should never use type(obj) == type_obj ; use the isinstance() function , always. Rarely do you need to ignore subclasses, and if you do need to ignore subclasses you can use type(obj) is type_obj instead.

isinstance() can take a tuple of types:

isinstance(obj, (int, long))

which then allows you to use a variable:

try:
    integer_types = (int, long)
except NameError:
    integer_types = int

if isinstance(obj, integer_types):

Note that I swapped out the integer_types definition based on a NameError here, not on a version test. Now your code is compatible with both Python 2 and 3, as well as with any other hypothetical Python build where there is no long type.

Generally, if I'm going to do type checking in python, I prefer to check against an abstract base class where possible. In this case, there exists numbers.Integral which might work nicely...

>>> import numbers
>>> isinstance(1, numbers.Integral)
True
>>> isinstance(1L, numbers.Integral)
True
>>> isinstance(1., numbers.Integral)
False

This should work on both python2.x and python3.x.


Of course, this answer (and all the others proposed so far) assume that you actually want to do the same thing if the number is an int or a long . Any code which wants to do something different depending on whether it has an int or long seems scary and it is hopeless to try to port that directly to python3.x as long simply does not exist making that codepath is effectively dead.

I like Martijn's answer, but would wrap it like

import sys

if sys.hexversion < 0x3000000:
    # Python 2.x
    is_int  = lambda x: isinstance(x, (int, long))
    is_long = lambda x: isinstance(x, long)
else:
    # Python 3.x
    is_int  = lambda x: isinstance(x, int)
    is_long = lambda x: False

which you can use like

if is_int(var):
    do_something(var)

or

if is_long(var):
    do_long_stuff(var)
elif is_int(var):
    do_int_stuff(var)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM