Skip to content

Instantly share code, notes, and snippets.

@gevorgyana
Created December 20, 2020 15:22
Show Gist options
  • Save gevorgyana/90d9878c4e8bb55eac8a966d9df55151 to your computer and use it in GitHub Desktop.
Save gevorgyana/90d9878c4e8bb55eac8a966d9df55151 to your computer and use it in GitHub Desktop.
metaclass
from inspect import getmembers, isroutine
class Descriptor:
def __init__(self, value):
self.value = value
def __get__(self, instance, owner):
print("get")
if self.value in instance.__slots__.keys():
return instance.__slots__[self.value]
else:
print('Not exists')
return None
def __set__(self, instance, value):
print("set")
instance.__slots__[self.value] = value
def __delete__(self, instance):
instance.__slots__[self.value] = None
class MetaA(type):
def __new__(mcs, *args, **kwargs):
variables = [a for a in args[2] if not (a.startswith('__') and a.endswith('__')) and not isroutine(args[2][a])]
args[2]['__slots__'] = {}
for var_name in variables:
args[2]['__slots__'][var_name] = args[2][var_name]
args[2].pop(var_name)
res = super().__new__(mcs, *args, **kwargs)
for key in args[2]['__slots__']:
flag = False
for name, value in getmembers(args[2]['__slots__'][key]):
if name == '__get__' or name == '__set__' or name == '__delete__' or name == '__set_name__':
flag = True
break
if flag:
setattr(res, key, args[2]['__slots__'][key])
args[2]['__slots__'][key] = None
def _setattr(self, _name, _value):
if _name not in self.__slots__:
print(f"Not allowed to assign '{_name}' with value '{_value}'")
return None
else:
return object.__setattr__(self, _name, _value)
res.__setattr__ = _setattr
return res
def __init__(cls, *args, **kwargs):
type.__init__(cls, *args, **kwargs)
def __call__(cls, *args, **kwargs):
print(cls.__slots__)
prev_values = cls.__slots__.copy()
new_obj = super().__call__(*args, **kwargs)
print(new_obj.__slots__)
for key in new_obj.__slots__:
if prev_values[key] is not None:
try:
exec(f'v = new_obj.{key}')
except:
exec(f"new_obj.{key} = {new_obj.__slots__[key]}")
return new_obj
class A(metaclass=MetaA):
foo = Descriptor("foo")
bar = 2
def __init__(self, foo):
self.foo = foo
def f(self):
print(self.foo)
print('hello there')
a = A(10)
print(a.bar)
print(a.foo)
a.bar = -1
a.foo = 12
del a.foo
a.foo = 10
a.zoo = 9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment