I am by no means a skilled coder, but I'll make this into a tutorial as best as I can. So let's walk through this step by step.
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.DB import *
import Autodesk
Here we import all the references necessary to interact with the Revit API.
doc = IN0
items = IN1
elementlist = list()
Next, we need to declare some variables. We could just keep using the automatically declared variables IN0 and IN1 from our input ports, but I prefer to keep my code readable, so I usually choose a variable name that describes what my input is exactly. (You could actually declare doc directly in Python without using a node as an input, but there was a time when this didn't work, so I got used to using the Revit Document node instead...) The elementlist is an empty list that will later be filled with stuff.
for item in items:
Iterate through every item in the input list. Notice how I'm using a custom node called Turn Into List between the list of parts and the Python node. I can't know whether the user wants to put in a list or just a single object. Also, my code is usually not fit to go through a list of lists. Turn Into List will convert a single value into a list of 1 item or a list of lists into a flat list.
sourcelist = list()
Declare another empty list. In theory, parts can have more than one parent object, so the GetSourceElementIds method will always return an ICollection (basically a glorified list). The sourcelist is reset to an empty list in every iteration (i.e. when looking at the next part), so it can work as a sublist of our elementlist.
for source in item.GetSourceElementIds():
Iterate through the list of elements that the GetSorceElementIds method will return for a given part.
BTW: Your code returned a list of items called IronPython.Runtime.Types.BuiltInFunction. That's because you called a method like GetSourceElementIds without adding brackets behind it. The brackets usually contain arguments for the method, but in the case of GetSourceElementIds no arguments are needed. If you look at Revit's API documentation, the members section is always divided into at least two subsections: methods and properties. This is how you would call them in python:
- object.method(args)
- object.property
sourcelist.append(doc.GetElement(source.HostElementId))
This next line looks a bit more complicated because there are several expressions nested into one another. First, source.HostElementId will get us the ID of the source object of the given part. Next, doc.GetElement() will get us a Revit Object for a given ID (the one we just found through source.HostElementId). Lastly, we can use sourcelist.append() to add that element to our list of source objects for the given part. If I weren't so lazy I could also write this in several lines to make it more legible:
elementID = source.HostElementId
element = doc.GetElement(elementID)
sourcelist.append(element)
And the last part:
if len(sourcelist) < 2:
elementlist.append(sourcelist[0])
else:
elementlist.append(sourcelist)
In most cases, each part will only have a single source element, so what I'm doing here is not returning a sublist of source elements if it isn't necessary (probably 98% of all cases...). So basically, sourcelist[0] gets me the first item of sourcelist.
I hope this helps a bit. Usually, for a node like this, I would try to make it safer. If you feed elements that aren't parts into this node it will throw an exception, because the GetSourceElementIds method is specifically designed for parts. If you look at some of my custom nodes you will find a try/except structure that can keep the node from turning red.
(EDIT: Just realized that the try/except bit is in your code already...) :-)
Lastly, professional coders might cringe at some of what I've written here, but so far it's worked for me... ;-)