The proposed answers should not be considered as the most correct. Moreover, I hope that more experienced people will point out mistakes, inaccuracies and bad places. For which they thank in advance.
class Observable(object): """ Base class for attributes from dict. >>> class X(Observable): ... pass >>> x = X(foo=1, bar="Test", _barr='hidden', baz=(5, 6)) >>> print x X(bar=Test, foo=1, baz=(5, 6)) >>> print x.foo 1 >>> print x.bar Test >>> print x._barr hidden >>> print x.baz (5, 6) """ def __init__(self, **kwargs): self.__dict__.update(kwargs) def __str__(self): return '%s(%s)' % (self.__class__.__name__,\ (', '.join('%s=%s' % (key, val) for (key, val)\ in self.__dict__.iteritems() if not key.startswith('_'))))
class DictAttr(dict): """ Base class for JS-style dict. >>> x = DictAttr([('one', 1), ('two', 2), ('three', 3)]) >>> print x {'three': 3, 'two': 2, 'one': 1} >>> print x['three'] 3 >>> print x.get('two') 2 >>> print x.one 1 >>> print x.test Traceback (most recent call last): ... AttributeError """ def __getattr__(self, name): try: return self[name] except KeyError: raise AttributeError
class XDictAttr(dict): """ >>> class X(XDictAttr): ... def get_foo(self): ... return 5 ... def get_bar(self): ... return 12 ... def get_get_z(self): ... return 42 >>> x = X({'one': 1, 'two': 2, 'three': 3}) >>> x {'one': 1, 'three': 3, 'two': 2} >>> x['one'] 1 >>> x.three 3 >>> x.bar 12 >>> x['foo'] 5 >>> x.get('foo', 'missing') 5 >>> x.get('bzz', 'missing') 'missing' >>> x.get_bar() 12 >>> x.get_foz() Traceback (most recent call last): ... AttributeError >>> x.get_get_z() 42 >>> x.get('get_z') 42 >>> x.get_z Traceback (most recent call last): ... AttributeError """ def __getattr__(self, name): try: return super(XDictAttr, self).__getitem__(name) except KeyError: if not name.startswith('get_'): return getattr(self, 'get_%s' % name)() else: raise AttributeError def __getitem__(self, key): try: return super(XDictAttr, self).__getitem__(key) except KeyError: return getattr(self, 'get_%s' % key)() def get(self, key, default=None): try: return getattr(self, 'get_%s' % key)() except AttributeError: return super(XDictAttr, self).get(key, default)
>>> for i in Reg: ... print i <Reg instance at 0x98b6ecc> <Reg instance at 0x98b6fec> <Reg instance at 0x98ba02c>
class RegBase(type): def __iter__(cls): return iter(cls._instances) class Reg(object): """ >>> x = Reg() >>> x # doctest: +ELLIPSIS <__main__.Reg object at 0x...> >>> y = Reg() >>> y # doctest: +ELLIPSIS <__main__.Reg object at 0x...> >>> z = Reg() >>> z # doctest: +ELLIPSIS <__main__.Reg object at 0x...> >>> for i in Reg: # doctest: +ELLIPSIS ... print i <__main__.Reg object at 0x...> <__main__.Reg object at 0x...> <__main__.Reg object at 0x...> """ __metaclass__ = RegBase _instances = [] def __init__(self): self._instances.append(self)
class Property(object): """ >>> class Image(object): ... height = Property(0) ... width = Property(0) ... path = Property('/tmp/') ... size = Property(0) >>> img = Image() >>> img.height = 340 >>> img.height 340 >>> img.path = '/tmp/x00.jpeg' >>> img.path '/tmp/x00.jpeg' >>> img.path = 320 Traceback (most recent call last): ... TypeError """ def __init__(self, value): self.__value = value self.__value_type = type(value) def __get__(self, obj, objtype=None): return self.__value def __set__(self, obj, value): if type(value) == self.__value_type: self.__value = value else: raise TypeError
class ImageMeta(type): def __new__(mcs, name, bases, dct): for key, val in dct.iteritems(): if not key.startswith('_') and not hasattr(val, '__call__'): dct[key] = Property(val) return type.__new__(mcs, name, bases, dct) class ImageBase(object): """ >>> class Image(ImageBase): ... height = 0 ... path = 'tmp' ... ... def foo(self): ... return 'bar' >>> img = Image() >>> img.height = 340 >>> img.height 340 >>> img.path = '/tmp/x00.jpeg' >>> img.path '/tmp/x00.jpeg' >>> img.path = 320 Traceback (most recent call last): ... TypeError >>> hasattr(img.foo '__call__') True """ __metaclass__ = ImageMeta
class Property(object): """ >>> class Image(object): ... size = Property(int) ... name = Property(basestring) >>> img = Image() >>> img.size = 0 >>> img.size 0 >>> img.name = '/tmp/img' >>> img.name '/tmp/img' >>> img.size = '~' Traceback (most recent call last): ... TypeError >>> img.name = ['/tmp/', 'img'] Traceback (most recent call last): ... TypeError >>> img.__class__.__dict__['size'].counter 0 >>> img.__class__.__dict__['name'].counter 1 """ counter = 0 def __init__(self, value_type): self.__value = None self.__value_type = value_type self.counter = Property.counter Property.counter += 1 def __get__(self, obj, objtype=None): return self.__value def __set__(self, obj, value): if isinstance(value, self.__value_type): self.__value = value else: raise TypeError class Integer(Property): def __init__(self): super(Integer, self).__init__(int) def __str__(self): return self.__class__.__name__.upper() class Str(Property): def __init__(self, size): super(Str, self).__init__(basestring) self.__size = size def __str__(self): return '{0}({1})'.format('varchar', self.__size).upper() class TableMeta(type): def __new__(mcs, name, bases, dct): fields = [(attr_name, val) for (attr_name, val) in dct.items()\ if isinstance(val, Property)] fields.sort(key=lambda x: x[1].counter) sql = ',\n'.join('\t{0} {1}'.format(attr_name, val)\ for (attr_name, val) in fields) dct['__sql'] = u'CREATE TABLE {0} (\n{1}\n)'.format(name, sql) return type.__new__(mcs, name, bases, dct) class Table(object): """ >>> class Image(Table): ... height = Integer() ... width = Integer() ... path = Str(128) >>> print Image.sql() # doctest: +NORMALIZE_WHITESPACE CREATE TABLE Image ( height INTEGER, width INTEGER, path VARCHAR(128) ) """ __metaclass__ = TableMeta @classmethod def sql(cls): return cls.__dict__['__sql']
Source: https://habr.com/ru/post/147783/
All Articles