[Maya][Python] Formatting arguments for a function that works on a mesh or vertices

I have some functions that can either work on a full mesh or on a set of components and I’m not sure how to handle the arguments for that. I see a couple options:

[ol]
[li]Mimic Maya’s argument looseness and accept either a mesh or a list of components as the first argument. It would determine which has been passed in and proceed accordingly.[/li][li]Have them as separate keyword arguments: mesh=None, components=None. Only one can be passed. The thing with this is that if I have a function that has positional arguments, then you end up passing the object(s) being operated on (mesh/components) after the positional arguments, which seems counterintuitive, like:[/li]

def exportWeights(outpath, mesh=None, components=None)

[li]Have the first argument be the mesh, and have a keyword argument to specify a subset of components to operate on, like:[/li]

def exportWeights(mesh, outpath, components=None)

If you prefer that method, what format would you expect the components to be in? A list of integer ids? A list of component strings (“pCube1.vtx[2:5]”, “pCube1.vtx[10]”)?
[/ol]

I’m tempted to use the first method since although it is not pythonic, it matches the behavior of other Maya functions that can work on a full mesh or a set of components.

I use the first, because it matches the behavior of other Maya functions. Consistency over “correctness”.

I have a special Class for accepting a general selection and parsing/filtering/converting it into what each function needs.

How do you determine what type gets passed in? Do you check if something is an instance of basestring? If it’s a list or tuple?

It’s not a major point, but that actual functions should probably be written separately unless they are basically one liner or otherwise identical. It’s way easier to write and maintain functions where you know what you’re dealing with; if you have to if-check all over the function things will be harder to maintain and debug. Then, if you really need then to share a common interface, use a wrapper that picks the appropriate function:



def do_something_with_components(*comps):
     pass

def do_something_with_meshes(*meshes):
     pass

def something_tool(components = (,), meshes = (,):
     component_results = do_something_with_components(*components)
     mesh results = do_something_with_meshes(*meshes)
     return mesh_results + component results

In general though would not bother with the combined function unless you’re giving it to other technical users who will care about mimicking Maya’s style - if you or your team are the customers, stick with a simple and clear public face that doesn’t try to resolve ambiguities – it’s just easier to write, read, and maintain.

FWIW In this specific case you can easily down-cast from meshes to components:


     def do_something_with_meshes(*meshes):
          faces = [m + ".f[li]" for  m in meshes] [/li]          return do_something_with_faces (*faces)

maya’s selection is always a list, so that is what gets passed in to my selection filter class.

so if my function needs UVs, I pass the current selection to the class and ask it for Uvs. If I don’t get anything back, then I can raise or early out.