开发者

"TypeError: Can't convert 'int' object to str implicitly" Trying to rename files in python3

I wrote the following function to rename a series of JPGs. They come off the scanner as a sequential number, however I need to know what the front and back of each document is (in JPG form)开发者_运维问答. How I chose to do this is make one end in A, and one end in B. For example:

  • 00001.jpg becomes 00001B.jpg
  • 00002.jpg becomes 00001A.jpg
  • 00003.jpg becomes 00002B.jpg
  • 00004.jpg becomes 00002A.jpg

This is because the scanner has a peculiar behavior, where the back is scanned before the front of each document.

I wrote the following function to handle this:

def make_page_denotation(rename_directory, extension, rename_files):
    for filename in glob(rename_files):
        sequential_number = int(filename[-9:-4])
        if sequential_number & 1 == True:
            os.rename(filename, filename.replace(str(sequential_number), str(sequential_number) + "B"))

        if sequential_number & 1 == False:
            os.rename(filename, filename.replace(int(sequential_number), int(sequential_number) - 1))
            os.rename(filename, filename.replace(str(sequential_number), str(sequential_number) + "A"))

However, I am getting the following error:

> Traceback (most recent call last):
  File "imageqa.py", line 311, in <module>
    imageqa_misc.make_page_denotation(rename_directory, extension, rename_files)
  File "/home/mylan/workspace/Working/Image-QA/imageqa_misc.py", line 68, in make_page_denotation
    os.rename(filename, filename.replace(int(sequential_number), int(sequential_number) - 1))
TypeError: Can't convert 'int' object to str implicitly

I can't figure out, for the life of me why this is happening. I'm still new to Python and programming in general, and am writing a series of scripts to help me out in everyday life to "dive right in" so any help would be greatly appreciated! The odd test (first block) works perfectly on its own, so I'm not sure how I messed up the second block.


0) Don't compare to boolean literals. Just use the condition directly.

1) Don't write "if <something>" and then "if <not something>". That's what else is for.

2) % 2 is a clearer parity test than & 1.

3) Your logic is wrong: you're subtracting 1 from the even numbers and leaving the odd numbers untouched, so you'd get 1, 1, 3, 3, 5, 5... instead of 1, 1, 2, 2, 3, 3 as desired. You need a division by 2 in there. The simple way is to add 1, divide by 2 (in integer arithmetic, this discards the remainder), and then append either an 'A' or a 'B' according to the parity.

4) The error message tells you exactly what's wrong. TypeError: Can't convert 'int' object to str implicitly means exactly what it says. replace replaces some substring in a string with another string. You can't replace an int within the string with another int, because the string doesn't contain ints (it merely contains substrings that can be interpreted as ints), and won't store any ints that you try to put into it.

Even if you could do this, there would be no way for the implicit conversion to know how many leading zeroes to use in the replacement.

The way we deal with this is to convert explicitly, of course. That's what int is doing in your code: explicitly converting the string to an integer. The calls to str in your code are useless, because explicitly converting a string to a string does nothing.

So the logic is:

a) Extract the part we're going to replace, and explicitly convert to int.

b) Do math to get the integer part of the replacement.

c) Use string formatting to create a string that contains (a) a zero-padded string representation of the new integer; (b) either 'A' or 'B' as a suffix.

d) Replace the part we're going to replace with that replacement. Instead of searching for the text again and replacing it, we'll just splice the replacement into where the original was - that's more direct, and avoids mistakes (e.g. if the file name happens to contain another copy of the number earlier on).

def make_page_denotation(rename_directory, extension, rename_files):
    for filename in glob(rename_files):
        original = int(filename[-9:-4]) # a)
        new_value = (original + 1) / 2 # b)
        replacement = ('%05d' % new_value) + ('B' if original % 2 else 'A') # c)
        new_filename = filename[:-9] + replacement + filename[-4:] # d)
        os.rename(filename, replacement)


>>> for fname in "00001.jpg","00002.jpg","00003.jpg","00004.jpg":
...     seq=int(fname[-9:-4])
...     print "%05d%s.jpg"%((seq+1)/2,"BA"[seq%2])
... 
00001A.jpg
00001B.jpg
00002A.jpg
00002B.jpg


In filename.replace(int(sequential_number), int(sequential_number) - 1), the two arguments to str.replace must be strings, you're passing in integers, which the traceback tells you. Try filename.replace(int(sequential_number), str(int(sequential_number) - 1))..

Also, what are you trying to do with sequential_number & 1? Check if the number is even? Why not just sequential_number % 2 == 0? That's clearer to read.


Even if your question is solved now, I have a reommendation:

if sequential_number & 1 == True:
    <stuff B>
if sequential_number & 1 == False:
    <stuff A>

is quite ugly. Better do this:

if sequential_number & 1:
    <stuff B>
else:
    <stuff A>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜