Note Updated as requested to shorter code and question. Hope this helps.
I am trying to understand the various ways in which one could create class properties (e.g., like @property for instance attributes, but for class attributes/variables). I've tried out some of the suggestions on here (e.g., Using property() on classmethods and How to make a class property?).
In short, it looks like using the meta-class methodology recommended for Python 3.x in "Using property() on classmethods" results in the attribute actually not being preserved (see test results). I'm wondering if either I made a mistake, or if someone could explain why what I see is the expected and right behavior.
Note that the code from "How to make a class property?" seems to behave as I would expect, but I tested the "best" answer in "How to make a class property?" and it is not behaving as I expected.
The Code
Trying to figure things out, I wrote some test code for the meta-class method specified for Python 3.x:
class SomeClassMeta(type):
    meta_attr = "SomeClassMeta Default meta_attr"
    # From https://stackoverflow.com/questions/128573/using-property-on-classmethods
    def __init__(self, *args, **kwargs):
        self.meta_attr = "SomeClassMeta.__init__() set meta_attr"
        pass
    @property
    def meta_prop(self):
        return self.meta_attr
    @meta_prop.setter
    def meta_prop(self, val):
        self.meta_attr = val
        pass
class ClasspropertyDescriptor(object):
    # From  https://stackoverflow.com/questions/5189699/how-to-make-a-class-property
    def __init__(self, fget, fset=None):
        self.fget = fget
        self.fset = fset
    def __get__(self, obj, klass=None):
        """Get it."""
        if klass is None:
            klass = type(obj)
        return self.fget.__get__(obj, klass)()
    def __set__(self, obj, value):
        """Set it."""
        if not self.fset:
            raise AttributeError("can't set attribute")
        type_ = type(obj)
        return self.fset.__get__(obj, type_)(value)
    def setter(self, func):
        """Set some class value."""
        if not isinstance(func, (classmethod, staticmethod)):
            func = classmethod(func)
        self.fset = func
        return self
def classproperty(func):
    # From  https://stackoverflow.com/questions/5189699/how-to-make-a-class-property
    if not isinstance(func, (classmethod, staticmethod)):
        func = classmethod(func)
        pass
    return ClasspropertyDescriptor(func)
class ClasspropertyMetaClass(type):
    def __setattr__(self, key, value):
        if key in self.__dict__:
            obj = self.__dict__.get(key)
        if obj and type(obj) is ClasspropertyDescriptor:
            return obj.__set__(self, value)
        return super(ClasspropertyMetaClass, self).__setattr__(key, value)
class SomeClass(metaclass=SomeClassMeta):
    class_attr = "SomeClass Default class_attr"
    norm_attr = "SomeClass Default norm_attr"
    inst_attr = "SomeClass Default inst_attr"
    _name = "SomeClass"
    def __init__(self,name):
        """Init this."""
        self.inst_attr = "SomeClass.__init__() set inst_attr"
        self._name = name
        pass
    @property
    def norm_prop(self):
        return self.norm_attr
    @norm_prop.setter
    def norm_prop(self, val):
        self.norm_attr = val
        pass
    @classproperty
    def class_prop(self):
        return self.class_attr
    @class_prop.setter
    def class_prop(self, val):
        self.class_attr = val
        pass
    @property
    def inst_prop(self):
        """Get the instance variable (attribute)."""
        return self.inst_attr
    @inst_prop.setter
    def inst_prop(self, val):
        self.inst_attr = val
        pass
    def _info(self,attr):
        attrval = getattr(self,attr,'No Such Attribute')
        attrcval = getattr(self.__class__,attr,'No Such Attribute')
        print(f" - {self._name}.{attr} = '{attrval}', {self._name}.__class__.{attr} = '{attrcval}'")
        if isinstance(attrval,property):
            print(f" - {self._name}.{attr}.__get__() = '{attrval.__get__(self)}'")
    def info(self):
        print(f"{self._name} is a {type(self).__name__}")
        for attr in [
                'class_prop',
                'class_attr',
                'inst_attr',
                'inst_prop',
                'meta_attr',
                'meta_prop',
                'norm_attr',
                'norm_prop',
                ]:
            self._info(attr)
            self.__class__._info(self.__class__,attr)
Some_Inst = SomeClass('Some_Inst')
Some_Inst.class_prop = "Set with Some_Inst.class_prop"
Some_Inst.inst_prop = "Set with Some_Inst.inst_prop"
Some_Inst.meta_prop = "Set with Some_Inst.meta_prop"
Some_Inst.norm_prop = "Set with Some_Inst.norm_prop"
Some_Inst.info()
The Output
Some_Inst is a SomeClass
 - Some_Inst.class_prop = 'Set with Some_Inst.class_prop', Some_Inst.__class__.class_prop = 'Set with Some_Inst.class_prop'
 - SomeClass.class_prop = 'Set with Some_Inst.class_prop', SomeClass.__class__.class_prop = 'No Such Attribute'
 - Some_Inst.class_attr = 'Set with Some_Inst.class_prop', Some_Inst.__class__.class_attr = 'Set with Some_Inst.class_prop'
 - SomeClass.class_attr = 'Set with Some_Inst.class_prop', SomeClass.__class__.class_attr = 'No Such Attribute'
 - Some_Inst.inst_attr = 'Set with Some_Inst.inst_prop', Some_Inst.__class__.inst_attr = 'SomeClass Default inst_attr'
 - SomeClass.inst_attr = 'SomeClass Default inst_attr', SomeClass.__class__.inst_attr = 'No Such Attribute'
 - Some_Inst.inst_prop = 'Set with Some_Inst.inst_prop', Some_Inst.__class__.inst_prop = '<property object at 0x7fdc48c594a8>'
 - SomeClass.inst_prop = '<property object at 0x7fdc48c594a8>', SomeClass.__class__.inst_prop = 'No Such Attribute'
 - SomeClass.inst_prop.__get__() = 'SomeClass Default inst_attr'
 - Some_Inst.meta_attr = 'SomeClassMeta.__init__() set meta_attr', Some_Inst.__class__.meta_attr = 'SomeClassMeta.__init__() set meta_attr'
 - SomeClass.meta_attr = 'SomeClassMeta.__init__() set meta_attr', SomeClass.__class__.meta_attr = 'SomeClassMeta Default meta_attr'
 - Some_Inst.meta_prop = 'Set with Some_Inst.meta_prop', Some_Inst.__class__.meta_prop = 'SomeClassMeta.__init__() set meta_attr'
 - SomeClass.meta_prop = 'SomeClassMeta.__init__() set meta_attr', SomeClass.__class__.meta_prop = '<property object at 0x7fdc48c59908>'
 - Some_Inst.norm_attr = 'Set with Some_Inst.norm_prop', Some_Inst.__class__.norm_attr = 'SomeClass Default norm_attr'
 - SomeClass.norm_attr = 'SomeClass Default norm_attr', SomeClass.__class__.norm_attr = 'No Such Attribute'
 - Some_Inst.norm_prop = 'Set with Some_Inst.norm_prop', Some_Inst.__class__.norm_prop = '<property object at 0x7fdc48c596d8>'
 - SomeClass.norm_prop = '<property object at 0x7fdc48c596d8>', SomeClass.__class__.norm_prop = 'No Such Attribute'
 - SomeClass.norm_prop.__get__() = 'SomeClass Default norm_attr'
Questions
- Why do SomeClass.inst_propandSomeClass.norm_propreturn aproperty()while all otherproperty()s whether on the class or instance behave as expected (even after first instantiation)?
- I thought the purpose of the metaclass was to create a Class property. Why then does setting Some_Inst.meta_prop = "Set with Some_Inst.meta_prop"change the instance value but not the class value? Note that Some_Inst.class_prop behaves as I thought it would.
 
    