python - Determine if class attribute is a read-only data descriptor -


a read-only data descriptor descriptor defines both __get__ , __set__, __set__ raises attributeerror when called.

an example simple read-only property:

class test():      _i = 1      @property     def i(self):         return self._i  assert hasattr(test.i, '__get__') assert hasattr(test.i, '__set__') t = test() t.i # 1 t.i = 2 # error 

if have instance of class, can determine if instance attribute read-only data descriptor way (although don't @ all):

def is_ro_data_descriptor_from_instance(instance, attr):     temp = getattr(instance, attr)     try:         setattr(instance, attr, none)     except attributeerror:         return true     else:         setattr(instance, attr, temp)         return false 

if know class doesn't require arguments instantiated, can determine if class attribute read-only data descriptor similar above:

def is_ro_data_descriptor_from_klass(klass, attr):     try:         setattr(klass(), attr, none)     except attributeerror:         return true     else:         return false 

however, if don't know signature of class ahead of time, , try instantiate temporary object in way, error:

class myclass():     = 1     def __init__(self, a, b, c):         '''a, b, , c required!'''         pass  def is_ro_data_descriptor_from_klass(myclass, 'i') # error 

what can done determine if class attribute read-only data descriptor?

edit: adding more information.

below code trying working:

class staticvarsmeta(type):     '''a metaclass emulate "static variable" behavior of     other languages. example:           class test(metaclass = staticvarsmeta):             _i = 1             @property             def i(self):                 return self._i         t = test()         assert t.i == test.i'''     statics = {}     def __new__(meta, name, bases, dct):         klass = super().__new__(meta, name, bases, dct)         meta.statics[klass] = {}         key, value in dct.items():             if "_" + key in dct:                 meta.statics[klass][key] = set()                 if hasattr(value, '__get__'):                     meta.statics[klass][key].add('__get__')                 if hasattr(value, '__set__'):                     try:                         value.__set__(none, none)                     except attributeerror:                         continue                     else:                         meta.statics[klass][key].add('__set__')         return klass     def __getattribute__(klass, attr):         if attr not in staticvarsmeta.statics[klass]:             return super().__getattribute__(attr)         elif '__get__' not in staticvarsmeta.statics[klass][attr]:             return super().__getattribute__(attr)         else:             return getattr(klass, '_' + attr)     def __setattr__(klass, attr, value):         if attr not in staticvarsmeta.statics[klass]:             super().__setattr__(attr, value)         elif '__set__' not in staticvarsmeta.statics[klass][attr]:             super().__setattr__(attr, value)         else:             setattr(klass, '_' + attr, value)  class test(metaclass = staticvarsmeta):     _i = 1     def get_i(self):         return self._i     = property(get_i) 

note following:

type(test.i) # int type(test.__dict__['i']) # property test().i = 2 # error, expected test.i = 2 # no error - should produce error 

it seems super-awkward, here's how implement based on comment:

class staticvarsmeta(type):      statics = {}      def __new__(meta, name, bases, dct):         cls = super().__new__(meta, name, bases, dct)         meta.statics[cls] = {}         key, val in dct.items():             if hasattr(val, '__get__') , hasattr(val, '__set__'):                 meta.statics[cls][key] = {'__get__'}                 try:                     val.__set__(none, none)                 except attributeerror err:                     if "can't set attribute" in err.args:                         continue                 meta.statics[cls][key].add('__set__')         return cls 

in use:

>>> class readonly(metaclass=staticvarsmeta):     @property     def foo(self):         return none   >>> class readwrite(metaclass=staticvarsmeta):     @property     def bar(self):         return none     @bar.setter     def bar(self, val):         pass   >>> staticvarsmeta.statics {<class '__main__.readonly'>: {'foo': {'__get__'}},   <class '__main__.readwrite'>: {'bar': {'__get__', '__set__'}}} 

this more of "starter 10", there must better way it...


Comments

Popular posts from this blog

css - SVG using textPath a symbol not rendering in Firefox -

Java 8 + Maven Javadoc plugin: Error fetching URL -

node.js - How to abort query on demand using Neo4j drivers -