Instantiating a class, in python:
class A:
name = 'foo'
a = A()
The a variable now holds an instance of an A class. As per intended.
Now let’s extrapolate this into the domain of blender’s python.
class B(bpy.types.PropertyGroup):
name = bpy.props.StringProperty(default='bar')
If we expected to do b = B()
and have it work, well, then we would have a lot of expectations.
First off, subclasses of bpy.types.PropertyGroup need to be registered, before they are useful.
Next, look at the ‘name’ attribute for both A and B. With A, there are no restrictions on the type of ‘name’. It is a string, ‘foo’, but there is no logic that says it can’t be something else. If you assign an int value to name, then name will be an int. With class B, the name attribute has an intermediary between it and its value. The fact that this is a StringProperty means that when assigning to the name property, wrong types will not be assigned.
What happens in the first example where it says a = A()
?
Class A’s constructor method is called to return an initialized instance of an A …
and we’re going to keep it in a variable
and we’re going to call it “a”.
In the second example, doing that to B would circumvent blender’s ability to keep the instance of B that is returned. So even if the construction of the class went ok, a returned instance in the ‘b’ variable would be … floating out in space as far as blender is concerned.
During the registration phase, various things need to happen so that blender can translate some of the informations about the class into useful informations for itself. bpy.utils.register_class is called to do this, and once called, not even yet is class instantiated. If you do lots of classes, with register_module(name) then there is even a search, by blender, for subclasses of things it knows what to do with, and the classes can even be defined in other scripts and from . imported… whatever is visibly-named at the top level where you are doing the register_module, blender will register_class for each class in subclasses() of each registrable class.
BUT once all that is done, hopefully it is only to be done once. It doesn’t keep happening over and over unless something bad is happening.
Asking python for to make there to be a ‘b’ variable which is a usable instance of class B, to be directly returned upon instance-making, how then is blender to know about this? Short of altering the inner-workings of blender’s python interpreter to always tell blender about all of the classes that get instantiated, which would be all the things, all the time, mostly none of which blender needs to know about.
So, hopefully I have told you at least two things, which should be:
Blender is not going out of its way to search through all of the class instances everywhere more than once.
You can’t have init constructors for the various PropertyGroups, Panels and Operators you’re going to create, because blender needs them for itself.
You can, however create a method on a PropertyGroup, attach that to the scene via PointerProperty, and then call that method just after your registration phase, to provide the functionality of an ‘init’.
If all you wanted was creation parameters, then perhaps a from_params method on the class might do the trick.
Also, as a general rule, I only make the classes that blender will register descend from something that blender will register. Thus, classes that will be used as mix-ins, I don’t make descend from PointerProperty,Operator,Panel etcetera.
Also also, you’re running into the standard confusions about class dictionaries vs instance dictionaries. Consider the order that they are searched for attribute names, and that when an attribute name is found, that where it is found, it also stays. Setting a value in the class dict of one of your mix-ins is … exactly that.
These pointer properties, they are tricky. Consider it like the StringProperty, how the attribute was going to be managed. The ‘name’ property is always going to be a string, it has a default, but you can access it by referring to it and it will return you its value, which will ALWAYS be a string. The PointerProperty, it is the same way. It will always BE a PointerProperty. Attached to an object, it will be a property of that object, so that when you access it as a property of the object, the method that is called to “get” it will return to you – and here we have at last – an instance of the type of class it points to. If bpy.context.scene.joint = Joint(params)
were actually to take place, the scene’s ‘joint’ property would no longer be a PointerProperty to an instance of a Joint, it would be the actual instance, minus all of blender’s abilities to interact with it.
I’m not saying it can’t be done. I just don’t think there is a setattr on the PointerProperty that is going to know how to handle being set to an instance. Maybe you can try and it will work under controlled conditions, who knows?