尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

除了使用hash()函数,还有哪些方法可以判断变量是可变变量还是不可变变量?

除了使用hash()函数,还有哪些方法可以判断变量是可变变量还是不可变变量? 排除hash()下面把剩余可用方案全部整理同时讲清各自适用范围、缺陷方便你对比。方法 1使用collections.abc抽象基类推荐做代码判断MutableSequence/MutableMapping/MutableSet是 Python 内置的可变抽象类型。MutableSequencelistMutableMappingdictMutableSetsetfrom collections.abc import MutableSequence, MutableMapping, MutableSet def is_mutable(obj): return isinstance(obj, (MutableSequence, MutableMapping, MutableSet)) print(is_mutable([1,2])) # True list可变 print(is_mutable((1,2))) # False tuple不可变 print(is_mutable({a:1})) # True dict可变 print(is_mutable({1,2})) # True set可变 print(is_mutable(hello)) # False str不可变 print(is_mutable(123)) # False int不可变✅优点标准库语义清晰。 ❌局限自定义对象如果手动继承可变抽象类才会识别普通自定义实例默认返回 False但自定义对象本身可以写代码变成可变的。方法 2检测原地修改魔法方法__setitem__、__delitem__、append等__setitem__支持obj[x] vallist、dict 有str、tuple 没有。__delitem__支持del obj[x]。def has_inplace_modify(obj): return hasattr(obj, __setitem__) or hasattr(obj, __delitem__) print(has_inplace_modify([1,2])) # True print(has_inplace_modify({a:1})) # True print(has_inplace_modify((1,2))) # False print(has_inplace_modify(abc)) # False⚠️重大缺陷set没有__setitem__set使用add/discard该方法识别不出 set。s {1,2} print(hasattr(s, __setitem__)) # False但set是可变方法 3原地操作 id()对比原理验证调试用⚠️关键点必须执行原地修改操作不能做重新赋值obj xxx。 逻辑执行原地修改操作前后对比id()id 不变 → 可变id 改变 → 不可变lst [1,2] old id(lst) lst.append(3) print(id(lst) old) # True →可变 t (1,2) old id(t) t t (3,) # ⚠️这是重新赋值不是原地修改不能用来测试元组❌缺点 不同对象需要调用不同原地方法不能写一个通用函数只能用于手动调试学习。方法 4尝试执行原地修改捕获异常暴力测试尝试做原地修改成功 可变抛异常 不可变。注意要复制一份对象避免把原变量改坏。def test_mutable(obj): import copy o copy.deepcopy(obj) try: # 序列类型尝试索引赋值 o[0] o[0] return True except (TypeError, IndexError): pass try: # set尝试add o.add(99999) return True except (TypeError, AttributeError): pass try: # dict尝试赋值key o[_test_key_] 1 return True except (TypeError, AttributeError): pass return False print(test_mutable([1,2])) # True print(test_mutable({1,2})) # True print(test_mutable({a:1})) # True print(test_mutable((1,2))) # False print(test_mutable(abc)) # False print(test_mutable(123)) # False✅可以处理 list /dict/set。 ❌缺点代码复杂要处理各种类型接口自定义对象行为不可控会修改拷贝出来的对象。方法 5深浅拷贝行为辅助判断仅用于理解不适合做判断逻辑规则不可变对象copy.copy()大多直接返回自身引用不变。可变对象copy.copy()返回新对象id 变化。import copy a [1,2] b copy.copy(a) print(id(a) ! id(b)) # True 可变 t (1,2) t2 copy.copy(t) print(id(t) id(t2)) # True 不可变⚠️坑元组里面全部是不可变元素时dysuia.cn 浅拷贝复用对象但元组内含 list 时浅拷贝依然生成新元组。不能作为可靠判断依据仅用来理解底层。各方案优缺点汇总排除 hash表格方案优点缺点collections.abc 抽象基类标准库代码简洁自定义类识别有局限检测魔法方法__setitem__简单识别不出 setid () 对比原地修改看底层原理不能写通用函数需要针对不同类型调用不同原地 API暴力原地修改 异常捕获支持 list/dict/set代码冗长需要拷贝对象自定义对象不可控深浅拷贝对比 id辅助理解存在特例不能正式用来判断实际开发建议写代码自动判断优先用collections.abc学习调试用id() 原地操作不推荐暴力修改、深浅拷贝做正式判断。补充hash()虽然好用但遇到(1,[2])这种内部带可变元素的元组会报错所以抽象基类是工程上更稳妥的替代。如果你需要我可以给你一份最终版不依赖 hash () 的完整健壮的判断函数。
返回列表