TypeError: NoneType - When using return zip_longest

TypeError: NoneType - When using return zip_longest

我现在收到 NoneType 的类型错误(我假设当我尝试 return 函数中的值 zip_longest)

我的代码 objective 是删除小于 "width = 400 AND height = 400" 的图像文件,然后将所有剩余图像放入 x 值的文件夹中(以后可以更改 x)。目前代码似乎可以工作,但我遇到了我提到的问题并希望防止该错误。

代码:

# ======== grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx:
def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    print(fillvalue)
    return zip_longest(*args, fillvalue=fillvalue)


def makedirs(d):
    try:
        os.makedirs(d)
    except OSError as e:
        # If the file already exists, and is a directory
        if e.errno == errno.EEXIST and os.path.isdir(d):
            created = False
        # It's some other error, or the existing file is not a directory
        else:
            raise
    else:
        created = True

    return created


def get_valid_filenames(directory, extensions):
    for filename in os.listdir(directory):
        if filename.lower().endswith(extensions):
            yield filename


def get_too_small_image_filenames(directory, extensions=DEFAULT_IMAGE_EXTS,
                                  min_width=400, min_height=400):
    for filename in get_valid_filenames(directory, extensions):
        image_path = os.path.join(directory, filename)
        try:
            with open(image_path, 'rb') as filehandle:
                img = Image.open(filehandle)
                width, height = img.size
        except IOError, e:
                yield filename

        if (width < min_width) and (height < min_height):
            yield filename


def confirm_it(directory, extensions, images_per_dir=500):
    # Confirm selection and move files to new sub-directory

        for too_small_filename in get_too_small_image_filenames(directory):
            os.remove(os.path.join(directory, too_small_filename))

        valid_images = get_valid_filenames(directory, extensions)
        grouped_image_file_names = grouper(valid_images, images_per_dir)
        for subdir, image_filenames in enumerate(grouped_image_file_names):
            for filename in image_filenames:
                from_path = os.path.join(directory, filename)

                to_dir = os.path.join(directory, "Folder ("+str(subdir)+")")
                to_path = os.path.join(to_dir, filename)

                makedirs(to_dir)
                os.rename(from_path, to_path)


def confirm_it_wrapper():
    confirm_it(directory=folderPath.get(), extensions=extensions)

回溯:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 1486, in __call__
    return self.func(*args)
  File "C:\Users\Gavin\workspace\Test Projects\src\Test0.py", line 109, in confirm_it_wrapper
    confirm_it(directory=folderPath.get(), extensions=extensions)
  File "C:\Users\Gavin\workspace\Test Projects\src\Test0.py", line 99, in confirm_it
    from_path = os.path.join(directory, filename)
  File "C:\Python27\lib\ntpath.py", line 66, in join
    p_drive, p_path = splitdrive(p)
  File "C:\Python27\lib\ntpath.py", line 114, in splitdrive
    if len(p) > 1:
TypeError: object of type 'NoneType' has no len()

额外信息:

如前所述,我相信它来自函数 returning "zip_longest" 参数,其中 fillvalue 在创建时设置为 "None"。有什么解决办法吗?

谢谢。

问题是文件数不是images_per_dir的倍数,所以最后一组images_per_dir张图片补上了None张。将此 trim_grouper() 函数添加到您的代码中以解决此问题:

from itertools import takewhile

def trim_grouper(iterable, n, fillvalue=None):
    for group in grouper(iterable, n, fillvalue=fillvalue):
        yield tuple(takewhile((lambda x: x), group))

然后在confirm_it()中替换:

grouped_image_file_names = grouper(valid_images, images_per_dir)

与:

grouped_image_file_names = trim_grouper(valid_images, images_per_dir)

应该可以了。