I've figured out how to do this. As I expected, since IronPython compiles down to CLR, C# and IronPython objects can interact with each other just fine with no special treatment necessary. I've created a script which actually creates a new type of Component which can be referenced just fine from C#.
A brief word on my game's structure: Its solution has two projects: Game, and GameEngine. The Game is what is ultimately compiled into an EXE, and the GameEngine is compiled into a DLL which sits in the same directory.
This currently sits in the default content project, has no build action and is copied to the output directory.
Note that the Component class is a part of GameEngine, and so is compiled into GameEngine.dll. It also has nothing to do with XNA's GameComponent class and its methods don't need to be passed a GameTime object.
from GameEngine import *
# or: from GameEngine import Component
pc = PyComponent()
How the script is compiled and run
Just once within the game, I run this:
// Engine setup stuff. The scope can work with variables in the script by
// adding references, accessing/removing current references, etc.
// Each script COULD have its own scope but I have no reason to do that yet.
ScriptEngine PythonEngine = Python.CreateEngine();
ScriptScope DefaultScope = PythonEngine.CreateScope();
string filename = @"Content\ScriptTest.py";
ScriptSource script = PythonEngine.CreateScriptSourceFromFile(filename, Encoding.ASCII);
When the script gets executed, it creates its own instance of a PyComponent.
Of course you'll need to reference the IronPython library and the Microsoft Dynamic runtime. I've found I only need these four DLLs from the root folder of the IronPython download:
Add these references to your project, then these
using statements to your code (according to Embedding IronPython in a C# Application):
Obtaining a reference to the Python object
I'm not sure how I'd get a reference directly from the script, but I do have a roundabout way of doing that. In my engine design, all components automatically register themselves with the engine's component collection, so I can get a reference to the object through there. In a more specific case, you could just have new Python objects register themselves with a queue somewhere, so you create them and then immediately retrieve them.