Python中动态给类添加方法且不暴露到全局命名空间的实现方案
解决方案
你可以通过以下几种方案实现相同功能,同时避免全局命名空间泄露:
方案1:使用临时闭包作用域批量添加方法
适合需要批量添加多个静态方法的场景,所有内部辅助函数都仅在闭包内可见,完全不会泄露到全局:
# 仅执行一次的闭包函数,内部定义的所有函数都不会流出到全局 def _inject_parse_methods(): def _internal_parse_one_of(*list_of_possible_matches): parsers = as_parsers(list_of_possible_matches) if len(parsers) == 0: raise Exception("no parsers were provided") the_whole_expression = None for parser in parsers: the_whole_expression = parser if the_whole_expression is None else the_whole_expression.or_else(parser) return the_whole_expression # 绑定为静态方法,避免调用时自动传入类/实例参数 Parse.one_of = staticmethod(_internal_parse_one_of) # 其他要添加的静态方法都可以在这里定义、绑定 # 执行注入 _inject_parse_methods() # 可选:删除注入函数本身,进一步清理全局命名空间 del _inject_parse_methods # 原有测试代码完全无需修改 Parse.one_of( "x", "y", "z").test_pass("xavier", "x") Parse.one_of( "x", "y", "z").test_pass("yellow", "y") Parse.one_of( "x", "y", "z").test_pass("zebra", "z") Parse.one_of( "x", "y", "z", Parse.any_char).test_pass("abracadabra", "a")
方案2:绑定后直接删除全局变量
适合仅添加少量方法的场景,操作最简单:
def _internal_parse_one_of(*list_of_possible_matches): parsers = as_parsers(list_of_possible_matches) if len(parsers) == 0: raise Exception("no parsers were provided") the_whole_expression = None for parser in parsers: the_whole_expression = parser if the_whole_expression is None else the_whole_expression.or_else(parser) return the_whole_expression Parse.one_of = staticmethod(_internal_parse_one_of) # 直接删除全局命名空间中的临时函数,避免泄露 del _internal_parse_one_of # 原有测试代码完全无需修改 Parse.one_of( "x", "y", "z").test_pass("xavier", "x") Parse.one_of( "x", "y", "z").test_pass("yellow", "y") Parse.one_of( "x", "y", "z").test_pass("zebra", "z") Parse.one_of( "x", "y", "z", Parse.any_char).test_pass("abracadabra", "a")
方案3:使用类装饰器注入
适合需要给多个类复用同一批方法的场景:
def parse_method_extension(cls): def one_of(*list_of_possible_matches): parsers = as_parsers(list_of_possible_matches) if len(parsers) == 0: raise Exception("no parsers were provided") the_whole_expression = None for parser in parsers: the_whole_expression = parser if the_whole_expression is None else the_whole_expression.or_else(parser) return the_whole_expression cls.one_of = staticmethod(one_of) # 其他要添加的方法都可以在这里绑定 return cls Parse = parse_method_extension(Parse) # 原有测试代码完全无需修改 Parse.one_of( "x", "y", "z").test_pass("xavier", "x") Parse.one_of( "x", "y", "z").test_pass("yellow", "y") Parse.one_of( "x", "y", "z").test_pass("zebra", "z") Parse.one_of( "x", "y", "z", Parse.any_char).test_pass("abracadabra", "a")
注意:如果你的Parse类在定义时就允许直接修改类体,也可以直接把方法写到类定义内部,上述方案更适合你需要在类定义完成后,分模块动态扩展方法的场景。
内容的提问来源于stack exchange,提问作者Darren Oakey
相关产品推荐
相关产品推荐

