元类编程

2018-08-19  本文已影响0人  xin激流勇进

http://blog.jobbole.com/21351/
https://segmentfault.com/a/1190000011447445

proprety简单用法

from datetime import date, datetime


class User:
    def __init__(self, name, birthday):
        self.name = name
        self.birthday = birthday

    def get_age(self):
        return datetime.now().year - self.birthday.year

    @property
    def age(self):
        return datetime.now().year - self.birthday.year

    @age.setter
    def age(self, value):
        self.name = value


if __name__ == '__main__':
    user = User('Merry', date(year=1996, month=10, day=24))
    print(user.age)
    user.age = 'Bob'

getattrgetattribution

from datetime import datetime
from yuanlei import test

# print(getattr(test, 'Name'))


class User:
    def __getattr__(self, item):
        '''找不到类属性时调用'''
        return datetime.now()

    def __getattribute__(self, *args, **kwargs):
        '''无条件被调用,通过实例访问属性。
        如果class中定义了__getattr__(),
        则__getattr__()不会被调用(
        除非显示调用或引发AttributeError异常) '''

        print('in the getattribute')
        return object.__getattribute__(self, *args, **kwargs)

#
# user = User()
# print(getattr(user, 'a'))

class C(object):
    a = 'abc'

    def __getattribute__(self, *args, **kwargs):
        print("__getattribute__() is called")
        return object.__getattribute__(self, *args, **kwargs)

    #        return "haha"
    def __getattr__(self, name):
        print("__getattr__() is called ")
        return name + " from getattr"

    def __get__(self, instance, owner):
        '''如果class定义了它,则这个class就可以称为descriptor。
        owner是所有者的类,instance是访问descriptor的实例,
        如果不是通过实例访问,而是通过类访问的话,instance则为None。
        (descriptor的实例自己访问自己是不会触发__get__,而会触发__call__,
        只有descriptor作为其它类的属性才有意义。)
        (所以下文的d是作为C2的一个属性被调用) '''
        print("__get__() is called", instance, owner)
        return self

    def foo(self, x):
        print(x)


class C2(object):
    d = C()


if __name__ == '__main__':
    # c = C()
    c2 = C2()
    # print(c.a)
    # print(c.zzzzzzzz)
    c2.d
    # print(c2.d.zzzz)

属性描述符

'''
如果user是某个类的实例,那么user.age(以及等价的getattr(user,’age’))
首先调用__getattribute__。如果类定义了__getattr__方法,
那么在__getattribute__抛出 AttributeError 的时候就会调用到__getattr__,
而对于描述符(__get__)的调用,则是发生在__getattribute__内部的。
user = User(), 那么user.age 顺序如下:

(1)如果“age”是出现在User或其基类的__dict__中, 且age是data descriptor, 那么调用其__get__方法, 否则

(2)如果“age”出现在user的__dict__中, 那么直接返回 obj.__dict__[‘age’], 否则

(3)如果“age”出现在User或其基类的__dict__中

(3.1)如果age是non-data descriptor,那么调用其__get__方法, 否则

(3.2)返回 __dict__[‘age’]

(4)如果User有__getattr__方法,调用__getattr__方法,否则

(5)抛出AttributeError

'''
import numbers

class IntField:
    def __set__(self, instance, value):
        if isinstance(value, numbers.Integral):
            self.value = value
        else:
            raise ValueError('value is not int')

    def __get__(self, instance, owner):
        return self.value


class User:
    age = IntField()


user = User()
user.age = 22
print(user.age)
print(user.__dict__)

动态生成类

# class Hello:
#     def say_hello(self, name='world'):
#         print('hello %s' % name)


def say_hello(self, name='world'):
    print('hello %s' % name)

Hello = type('Hello', (object,), {'say_hello': say_hello})
print(Hello)

hello = Hello()
hello.say_hello()

元类

class SayMetaClass(type):

    def __new__(cls, name, bases, attrs, **kwargs):
        attrs['say_'+name] = lambda self, value, saying=name: print(saying+','+value+'!')
        # print(attrs)
        return super().__new__(cls, name, bases, attrs, **kwargs)


class Hello(object, metaclass=SayMetaClass):
    name = 'chen'

    def get_age(self):
        return 22

class Hi(metaclass=SayMetaClass):
    pass

# hello = Hello()
# hi = Hi()
# hello.say_Hello('Nihao')
# hi.say_Hi('HI')

class ListMetaclass(type):
    def __new__(cls, name, bases, attrs, **kwargs):
        attrs['add'] = lambda self, value: self.append(value)
        return super().__new__(cls, name, bases, attrs, **kwargs)


class MyList(list, metaclass=ListMetaclass):
    pass

L = MyList()
L.add(1)
L.add(2)
print(L)

ORM

class Field(object):
    def __init__(self, name, column_type):
        self.name = name
        self.column_type = column_type

    def __str__(self):
        return '<%s: %s>' % (self.__class__.__name__, self.name)


class StringField(Field):
    def __init__(self, name):
        super().__init__(name, 'varchar(100)')


class IntegerField(Field):
    def __init__(self, name):
        super().__init__(name, 'bigint')


class ModelMetaclass(type):

    def __new__(cls, name, bases, attrs):
        if name == 'Model':
            return super().__new__(cls, name, bases, attrs)

        print('Found model: %s' % name)
        mappings = dict()
        for k, v in attrs.items():
            if isinstance(v, Field):
                print('Found mapping: %s==>%s' % (k, v))
                mappings[k] = v
        for k in mappings.keys():
            attrs.pop(k)

        attrs['__mappings__'] = mappings
        attrs['__table__'] = name
        return super().__new__(cls, name, bases, attrs)


class Model(dict, metaclass=ModelMetaclass):

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError("'Model' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value

    def save(self):
        fields = []
        args = []
        for k, v in self.__mappings__.items():
            fields.append(v.name)
            args.append(getattr(self, k, None))
        sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join([str(i) for i in args]))
        print('SQL: %s' % sql)
        print('ARGS: %s' % str(args))


class User(Model):
    id = IntegerField('id')
    name = StringField('username')
    email = StringField('email')
    password = StringField('password')


u = User(id=12345, name='Batman', email='batman@nasa.org', password='iamback', test=123)
u.id = 100
u.save()


上一篇下一篇

猜你喜欢

热点阅读