mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	
		
			
	
	
		
			61 lines
		
	
	
	
		
			1.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			61 lines
		
	
	
	
		
			1.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | import itertools | ||
|  | 
 | ||
|  | 
 | ||
|  | class PseudoStr(str): | ||
|  |     pass | ||
|  | 
 | ||
|  | 
 | ||
|  | class StrProxy: | ||
|  |     def __init__(self, value): | ||
|  |         self.value = value | ||
|  |     def __str__(self): | ||
|  |         return self.value | ||
|  |     def __bool__(self): | ||
|  |         return bool(self.value) | ||
|  | 
 | ||
|  | 
 | ||
|  | class Object: | ||
|  |     def __repr__(self): | ||
|  |         return '<object>' | ||
|  | 
 | ||
|  | 
 | ||
|  | def wrapped_arg_combos(*args, | ||
|  |                        wrappers=(PseudoStr, StrProxy), | ||
|  |                        skip=(lambda w, i, v: not isinstance(v, str)), | ||
|  |                        ): | ||
|  |     """Yield every possible combination of wrapped items for the given args.
 | ||
|  | 
 | ||
|  |     Effectively, the wrappers are applied to the args according to the | ||
|  |     powerset of the args indicies.  So the result includes the args | ||
|  |     completely unwrapped. | ||
|  | 
 | ||
|  |     If "skip" is supplied (default is to skip all non-str values) and | ||
|  |     it returns True for a given arg index/value then that arg will | ||
|  |     remain unwrapped, | ||
|  | 
 | ||
|  |     Only unique results are returned.  If an arg was skipped for one | ||
|  |     of the combinations then it could end up matching one of the other | ||
|  |     combinations.  In that case only one of them will be yielded. | ||
|  |     """
 | ||
|  |     if not args: | ||
|  |         return | ||
|  |     indices = list(range(len(args))) | ||
|  |     # The powerset (from recipe in the itertools docs). | ||
|  |     combos = itertools.chain.from_iterable(itertools.combinations(indices, r) | ||
|  |                                            for r in range(len(indices)+1)) | ||
|  |     seen = set() | ||
|  |     for combo in combos: | ||
|  |         for wrap in wrappers: | ||
|  |             indexes = [] | ||
|  |             applied = list(args) | ||
|  |             for i in combo: | ||
|  |                 arg = args[i] | ||
|  |                 if skip and skip(wrap, i, arg): | ||
|  |                     continue | ||
|  |                 indexes.append(i) | ||
|  |                 applied[i] = wrap(arg) | ||
|  |             key = (wrap, tuple(indexes)) | ||
|  |             if key not in seen: | ||
|  |                 yield tuple(applied) | ||
|  |                 seen.add(key) |