Created
December 20, 2020 15:22
-
-
Save gevorgyana/90d9878c4e8bb55eac8a966d9df55151 to your computer and use it in GitHub Desktop.
metaclass
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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