将方法参数传递给过滤器列表的本地实例对象

pass method agument to local instance object for filter list

我想将 prent 方法中的参数转换为使用本地实例对象的过滤器来过滤列表结果。

这就是我大致想要的概念

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)])

这就是我实际做的

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)]))

我们可以使用 operator.attrgetter 从关键字参数名称和关联值创建合适的过滤函数。

为了演示此代码,我创建了一个简单的 Test 对象和一个 fields 函数。

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))

输出

['none_a', 'none_b', 'none_c', 'none_d']
['edfalse_a', 'edfalse_b']
['edtrue_c', 'edtrue_d']
['reqfalse_a', 'reqfalse_c']
['reqtrue_b', 'reqtrue_d']

这是一个处理多个关键字的新版本。仅返回通过所有过滤器测试的项目。我稍微更改了测试对象名称并添加了一个 print 调用 get_fields 以便更容易地查看发生了什么。此代码适用于 Python 2 和 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))

输出

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']

请注意,此代码可以处理任意数量的关键字,而不仅仅是两个。


我还包含了一个实验函数 get_fields_any,其中 returns 通过 any 过滤器的对象。它使用集合 result 来累积匹配的对象,因此它不保留顺序。此外,将未定义 __eq____hash__ 方法的对象放入集合中(或将它们用作 dict 键)是有风险的。有关详细信息,请参阅 __hash__ docs