我怎样才能重构/使这段代码变得更加pythonic?

时间:2013-12-14 13:17:27

标签: python

我有一个小程序,它使用pycparser来解析C头文件。代码,unfornatuley,有点蔓延到处处理不同的案例(例如下面的例子)。

使这更像Pythonic的最佳方法是什么?我考虑过case-statements,但那些在Python中不存在。将功能拆分为更小的功能是最好的方法吗?

def build_struct(decl):
    """ Recursively builds a structure from external definition.
    """
    _type = type(decl)
    if _type == TypeDecl:
        return build_struct(decl.type)
    elif _type == IdentifierType:
        return " ".join(decl.names)
    elif _type == ID:
        return ['ID', decl.name]
    elif _type == Struct:
        struct = c_types.structureDefinition()
        for d in decl.decls:
            field = build_struct(d)
            struct.add_field(field)
        return struct
    elif _type == Union:
        union = c_types.unionDefinition()
        for d in decl.decls:
            field = build_struct(d)
            union.add_field(field)
        return union
    elif _type == Enum:
        # not implemented yet... but don't raise an exception
        # unsure if there is any value in supporting enums
        return
    else:
        nested = build_struct(decl.type)
        if _type == Decl:
            if decl.bitsize:
                # fields with bitsize defined (i.e. valid:1)
                return c_types.fieldDefinition(decl.name,
                                               int(decl.bitsize.value))
            elif isinstance(nested, c_types.structureDefinition):
                # if it's a structure, assign it's name
                nested.name = decl.name
                return nested
            elif isinstance(nested, c_types.unionDefinition):
                # if it's a union, assign it's name
                nested.name = decl.name
                return nested
            elif isinstance(nested, int):
                # if it's an array, we will just return the total size
                return c_types.fieldDefinition(decl.name, nested)
            else:
                # fields w/o bitsized defined
                id = nested
                # using defined types, like uint32_t
                if id in c_types.size_d:
                    size = c_types.size_d[id]
                # using defined structures, like fast_ip
                elif id in c_types.structs:
                    return c_types.structs[id]
                else:
                    raise c_types.UnknownIdentifier(id)
                # regular fields, i.e. int count;
                return c_types.fieldDefinition(decl.name, int(size))

        elif _type == Typename:  # for function parameters
            raise c_types.NotImplemented
        elif _type == ArrayDecl:
            #raise c_types.NotImplemented
            dimval = decl.dim.value if decl.dim else ''
            id = nested
            # using defined types, like uint32_t
            if id in c_types.size_d:
                size = c_types.size_d[id]
            # using defined structures, like fast_ip
            elif id in c_types.structs:
                return c_types.structs[id]
            else:
                raise c_types.UnknownIdentifier(id)
            return int(dimval) * size
        elif _type == PtrDecl:
            raise c_types.NotImplemented
        elif _type == Typedef:
            id = nested
            # TODO -- this is very common... refactor
            if isinstance(id, c_types.structureDefinition):
                # typedef struct ...
                # TODO -- very similar to code above...
                id.name = decl.name
                return id
            if isinstance(id, c_types.unionDefinition):
                # typedef struct ...
                # TODO -- very similar to code above...
                id.name = decl.name
                return id
            # TODO -- change to c_types.fieldDefinition
            # TODO -- this is very common... refactor
            if id in c_types.size_d:
                # typdef uint32 unsigned long;
                c_types.size_d[decl.name] = c_types.size_d[id]
                return c_types.size_d[decl.name]
            elif id in c_types.structs:
                return c_types.structs[id]
            elif not id:
                # unhandled cases, like enum
                return
            else:
                raise c_types.UnknownIdentifier(id)
        elif _type == FuncDecl:
            raise c_types.NotImplementede

2 个答案:

答案 0 :(得分:0)

使用字典构建递归下降解析器:

struct_actions = {
    TypeDecl: parse_type_decl,
    IdentifierType: parse_identifier_type,
    Etc: parse_etc,
}

def build_struct(decl):
    function = struct_actions.get(type(decl))
    if function is None:
        raise InvalidToken

    return function(decl)

替代方案,使用更正式的递归下降解析器,使用OO构建具有异构对象的语法树:

http://www.llvmpy.org/llvmpy-doc/0.9/doc/kaleidoscope/PythonLangImpl2.html

答案 1 :(得分:0)

您正在使用类型调度。从Python 3.4开始,您可以使用dedicated decorator来执行此操作。此装饰器也以backport package的形式提供。

try:
    from functools import singledispatch
except ImportError:
    from singledispatch import singledispatch

@singledispatch
def build_struct(decl):
    # Don't know how to do the generic version
    return

@build_struct.register(TypeDecl)
def build_struct_typedecl(decl):
    return build_struct(decl.type)

@build_struct.register(IdentifierType)
def build_struct_identifier(decl)
    return " ".join(decl.names)

@build_struct.register(ID)
def build_struct_id(decl)
    return ['ID', decl.name]

# etc.

您可以将调度更接近班级本身;导入build_struct泛型函数并根据需要注册更多调度方法。