元类编程
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'
getattr和getattribution
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()