I would like to convert argument in prent method to filter list result with filter of an local instance object.
That is what I would like approximatively for the concept
def get_fields(path, editable=True): # If only editable (or opposite)
return list([f.name for f in fields(path) if f.editable]) # Do filter
def get_fields(path, required=True): # If only required (or opposite)
return list([f.name for f in fields(path) if f.required]) # Do filter
def get_fields(path): # If all
return list([f.name for f in fields(path)])
This is what i do actualy
def get_fields_editable(path):
return list(f.name for f in fields(path) if f.editable]))
def get_fields_required(path):
return list(f.name for f in fields(path) if f.required]))
def get_fields(path):
return list(f.name for f in fields(path)]))
We can use operator.attrgetter
to create a suitable filtering function from the keyword arg name and the associated value.
To demonstrate this code I created a simple Test
object, and a fields
function.
from operator import attrgetter
def get_fields(path, **kwargs):
# Create the filter function
# Assumes there will only ever be at most a single keyword arg
if kwargs:
key, val = kwargs.popitem()
func = attrgetter(key)
filter_func = func if val else lambda obj: not func(obj)
else:
filter_func = lambda obj: True
return [f.name for f in fields(path) if filter_func(f)]
class Test(object):
def __init__(self, name, editable, required):
self.name = name
self.editable = editable
self.required = required
def fields(path):
return [
Test(path + '_a', False, False),
Test(path + '_b', False, True),
Test(path + '_c', True, False),
Test(path + '_d', True, True),
]
print(get_fields('none'))
print(get_fields('edfalse', editable=False))
print(get_fields('edtrue', editable=True))
print(get_fields('reqfalse', required=False))
print(get_fields('reqtrue', required=True))
output
['none_a', 'none_b', 'none_c', 'none_d']
['edfalse_a', 'edfalse_b']
['edtrue_c', 'edtrue_d']
['reqfalse_a', 'reqfalse_c']
['reqtrue_b', 'reqtrue_d']
Here's a new version that handles multiple keywords. Only items that pass all of the filter tests are returned. I've changed the test object names slightly and added a print
call to get_fields
to make it easier to see what's going on. This code works on both Python 2 and Python 3.
from __future__ import print_function
from operator import attrgetter
# Return items that pass any of the filters
def get_fields_any(path, **kwargs):
seq = fields(path)
print('KW', kwargs)
result = set()
if kwargs:
for key, val in kwargs.items():
# Create the filter function
func = attrgetter(key)
filter_func = func if val else lambda obj: not func(obj)
# Apply it
result.update(filter(filter_func, seq))
else:
result = seq
return [f.name for f in result]
# Only return items that pass all filters
def get_fields(path, **kwargs):
seq = fields(path)
print('KW', kwargs)
if kwargs:
for key, val in kwargs.items():
# Create the filter function
func = attrgetter(key)
filter_func = func if val else lambda obj: not func(obj)
# Apply it
seq = list(filter(filter_func, seq))
return [f.name for f in seq]
class Test(object):
def __init__(self, name, editable, required):
self.name = name
self.editable = editable
self.required = required
def __repr__(self):
fmt = 'Test({name}, {editable}, {required})'
return fmt.format(**self.__dict__)
def fields(path):
return [
Test(path + ':FF', False, False),
Test(path + ':FT', False, True),
Test(path + ':TF', True, False),
Test(path + ':TT', True, True),
]
print(get_fields('__'))
print(get_fields('_F', required=False))
print(get_fields('_T', required=True))
print(get_fields('F_', editable=False))
print(get_fields('T_', editable=True))
print()
print(get_fields('FF', editable=False, required=False))
print(get_fields('FT', editable=False, required=True))
print(get_fields('TF', editable=True, required=False))
print(get_fields('TT', editable=True, required=True))
output
KW {}
['__:FF', '__:FT', '__:TF', '__:TT']
KW {'required': False}
['_F:FF', '_F:TF']
KW {'required': True}
['_T:FT', '_T:TT']
KW {'editable': False}
['F_:FF', 'F_:FT']
KW {'editable': True}
['T_:TF', 'T_:TT']
KW {'editable': False, 'required': False}
['FF:FF']
KW {'editable': False, 'required': True}
['FT:FT']
KW {'editable': True, 'required': False}
['TF:TF']
KW {'editable': True, 'required': True}
['TT:TT']
Note that this code can handle any number of keywords, not just two.
I've also included an experimental function get_fields_any
which returns the objects that pass any of the filters. It uses a set result
to accumulate the matching objects, so it doesn't preserve order. Also, putting objects that don't define __eq__
and __hash__
methods into sets (or using them as dict
keys) is risky. See the __hash__ docs
for details.