python if 判断

2020/03/05 技术

python if 判断

1. 背景

最近, 在使用 if 进行条件判断时, 遇到一个坑. 从而引发我对 if 使用的一些思考.

看一段demo代码:

import logging
import os
import pickle

from pybloom import BloomFilter


def load_bloom_filter(logger: logging.Logger, bloom_filter_file: str) -> BloomFilter:
    """  """
    logger.info("load_bloom_filter: {}".format(bloom_filter_file))
    if not bloom_filter_file:
        return

    # load bloom filter obj
    if os.path.exists(bloom_filter_file):
        try:
            with open(bloom_filter_file, "rb") as f:
                bloom_obj = pickle.load(f)

            if bloom_obj:
                return bloom_obj

        except Exception as e:
            logger.error(e, exc_info=True)
    else:
        logger.warning("bloom filter file not found: {}".format(bloom_filter_file))

    bloom_obj = BloomFilter(capacity=10000 * 10000, error_rate=0.001)
    dump_bloom_filter(logger=logger, bloom_filter=bloom_obj, bloom_filter_file=bloom_filter_file)
    return bloom_obj


def dump_bloom_filter(logger: logging.Logger, bloom_filter: BloomFilter, bloom_filter_file: str):
    """ """
    logger.info("dump_bloom_filter: {}".format(bloom_filter_file))
    if not bloom_filter_file:
        return

    with open(bloom_filter_file, "wb") as f:
        pickle.dump(bloom_filter, f)

    logger.info("success to dump bloom filter to file: {}".format(bloom_filter_file))


def demo():
    bloom_filter_file = "./abc.pkl"
    if os.path.exists(bloom_filter_file):
        os.remove(bloom_filter_file)

    for _ in range(5):
        load_bloom_filter(logger=logging, bloom_filter_file=bloom_filter_file)


if __name__ == '__main__':
    demo()

在这段代码中, 我使用 python-bloomfilter 对数据进行去重处理.

在执行demo() 时, 日志中出现 5 次 success to dump bloom filter to file: ./abc.pkl, 即新建 5 次 bloom_filter 对象.

按照逻辑, 理论上只会在第 1 次新建对象, 后面 4 次应该是直接从文件中加载 bloom_obj.

2. 解决问题

demo 处的代码非常简单, 问题就出在代码块:

    if bloom_obj:
        return bloom_obj

bloom_obj 作为一个类的实例, 为什么条件 if bloom_obj 不成立? if <class_instance> , 调用了类的哪个方法?

通过打断点调试, 发现 if bloom_obj, 进入到 BloomFilter 类的 __len__(self): 方法中.

class BloomFilter(object):

    def __len__(self):
        """Return the number of keys stored by this bloom filter."""
        return self.count

由于空的 bloom_obj, self.count 为 0, 所以if bloom_obj 不成立.

3. 思考

if <class_instance> 单纯根据 __len__ 判断吗?

如果类没有__len__ 方法, 会有什么结果?

在文章 Python 中一些特殊方法的自定义及作用 找到了答案:

像if v/if not v等,python会调用bool(v)方法,而bool(v)背后的调用时尝试调用 v.__bool__(),如果没有__bool__方法,就会尝试调用__len__方法,若这是返回0则 是False否则为True,这两个方法都没有的话只能按照默认处理了

Search

    Table of Contents