1

I am migrating one big project from Python 2 -> Python 3, the issue with comparison between "bytes" and "str" only found when the old code run into it and fail explicitly. If it falsely pass, i will not be aware. One example:

def read_var_startaddr(self, var_name):
#__get_var_name() will return bytes
if self.__get_var_name() == var_name:
    print("do something")        
return self.__get_startaddr() 

So i would like to fix this for the whole project, instead of waiting until something happens, there are twos things in my mind:

  1. Use Notepad++: Search the whole project with regular expression, and checking by eyes ... to make sure no unexpected replacement happen. Search with Notepad++
  2. I would like the create wrapper the basic operator "==" or "!=", with a purpose to auto convert and compare corresponding values.

My Question: With option 2, Is it possible to do wrap the basic operator, how to do it and what are the impacts it may cause? Is there better way?

Thanks a lot!

Community
  • 1
  • 1
ThLaVi
  • 13
  • 4

2 Answers2

0

One tool that would be able to do this more generally is the mypy type checker; that would be rather heavy-weight, but it would definitely find these issues.

It would probably find a lot of other issues, and it would generally be a major change to the program, so you'd have to evaluate it as a whole rather than specifically for this one issue.

Jiří Baum
  • 6,697
  • 2
  • 17
  • 17
0

Perhaps give 2to3 a try first (a tag you selected I assume unassumingly). It's built in with Python 3, and might save you a lot of time.


For number 2 specifically, you can overwrite the dunder method __eq__ in objects, and use that instead. Something like so:

class Item:
    def __init__(self, item):
        if isinstance(item, bytes):
            self._item = item
        elif isinstance(item, str):
            self._item = bytes(item, 'utf-8')
        elif isinstance(item, int):
            self._item = bytes(str(item), 'utf-8')
        else:
            raise Exception("Item must be of type bytes, str, or int.")

    def __eq__(self, other):
        if isinstance(other, bytes):
            return self._item == other
        elif isinstance(other, str):
            return self._item.decode("utf-8") == other
        elif isinstance(other, int):
            if self._item.isdigit():
                return int(self._item) == other
            else:
                raise Exception("Cannot compare non-int to int.")

Then all of the following would work:

item = Item("hello")

item == "hello"  # True
item == b"hello" # True
item = Item(100)

item == 100 # True
item == "100" # True
item == b"100" # True

Do note that all objects Item will now be comparable with respect to the new __eq__ we wrote. If you are wondering "is there a way to modify ALL == comparison signs", the answer is... technically yes, but I promise you it is not worth it. You would have to deal with the ast module and create some very confusing code.


You could also more simply create a function compare_str_bytes() that uses some of the code above to compare bytes and strings accordingly.

felipe
  • 7,324
  • 2
  • 28
  • 37
  • Thanks, with this i can use replacement to wrap around all my operands in all my comparison lines. – ThLaVi May 22 '20 at 03:46