Sometimes what we DON'T WANT is the go.
Have previously commented on questions / answers where the poster was indexing by number that indexing by name was "better" more readable etc. Then around about the time of this answer
Principled BSDF via Python API
I discovered that changing the blender language, also changed the socket names. (This appears to be no longer the case, notice though changing to Espanol has changed the node name)
>>> mix = D.materials['Material'].node_tree.nodes['Mezclar sombreadores']
>>> mix
bpy.data.materials['Material'].node_tree.nodes["Mezclar sombreadores"]
I DO NOT want to do this as I may not always know the correct index
number:
Once we have a reference to the node, the indices of the inputs. These are always in the same order.
>>> for i, s in enumerate(mix.inputs.values()):
... i, s.name, s.identifier
...
(0, 'Fac', 'Fac')
(1, 'Shader', 'Shader')
(2, 'Shader', 'Shader_001')
The inputs collection, like so many collections in blender, including making our own via bpy.props.CollectionProperty
is a built-in extension type. Such a collection can be indexed like a list or a dictionary, however unlike a dictionary items can have same name.
>>> type(mix.inputs)
<class 'bpy_prop_collection'>
>>> type(D.objects)
<class 'bpy_prop_collection'>
Some workarounds
Further to question method to search on the identifier, could:
Rename it

>>> mix.inputs[2].name = "Bob"
>>> mix.inputs.get("Bob")
bpy.data.materials['Material'].node_tree.nodes["Mezclar sombreadores"].inputs[2]
Create script to iterate over all nodes and change the socket names.
The name will remain as "Bob" for the blender session. It will revert back to "Shader" for new mix node or on save / re-open.
Kind of silly on one hand, on the other shows how simply one can totally stuff up any script that relies on object names
(0, 'Fac', 'Fac')
(1, 'Shader', 'Shader')
(2, 'Bob', 'Shader_001.001')
... notice this has also auto renamed the read-only identifier
property.
Monkey Patch
An example of monkey-patching a method onto a blender class.
This is using not the index in the inputs, rather the index 1 to signify this is the 2nd input socket with the same name. In hindsight perhaps returning the list, instead of passing the index.
Could instead use identifier here, but as noted above there is no guarantee.
import bpy
from collections import defaultdict
context = bpy.context
def wireup(name):
def getinput(self):
coll = getattr(self, name, {})
def _get(name, index=0, default=None):
sockets = defaultdict(list)
for k, v in coll.items():
sockets[k].append(v)
ret = sockets[name][index]
return ret if ret else default
return _get
return getinput
bpy.types.Node.getinput = property(wireup("inputs"))
bpy.types.Node.getoutput = property(wireup("outputs"))
Test in console.
>>> mix.getinput("Shader")
bpy.data.materials['Material'].node_tree.nodes["Mezclar sombreadores"].inputs[1]
>>> mix.getinput("Shader", 1)
bpy.data.materials['Material'].node_tree.nodes["Mezclar sombreadores"].inputs[2]
>>> mix.getinput("Shader", -1)
bpy.data.materials['Material'].node_tree.nodes["Mezclar sombreadores"].inputs[2]
Other suggestions would be a simple node group to wrap the mix node with io names of our choosing, or enumerating the input and output socket names to a panel in the node editor.
To sum up, in as much as can workaround, perhaps the "goto" method here is to use the index directly, ie that second shader input in a mix node is always in slot 2, and reflect the choice via comment or variable name.
# Mix Node
# Inputs
# (0, 'Fac')
# (1, 'Shader')
# (2, 'Shader')
shader_input_1 = mix.inputs[1] # "Shader"
shader_input_2 = mix.inputs[2]
id
(could lead to unexpected results if testing for equality) $\endgroup$getByIdentifier(inputs, "Shader_001")
can be replaced with a onelinernext((i for i in inputs if i.identifier == "Shader_001"), None)
$\endgroup$