Python类说明

元类说明

type

type:元类,python中所有类都由type创建

1
2
3
4
5
class = type(
name=cls_name,
bases=(pls_name,..),
dict={attr1: val1,...}
)
  • 参数

    • cls_name:类名称
    • bases:父类元组
    • dict:类方法、属性
  • 返回值:类的别名

元类作用

  • 拦截类创建->修改类->返回修改后的类(创建类对象

  • 元类的作用和函数相似

    • python并不关心类对象是否是由真正的元类创建
    • 可以指定元类为一个函数,而非继承自type的元类
  • 但仍应尽量将元类指定为继承自type的对象

    • 元类应用场景一般比较复杂,使用类可以更好的管理代码
    • 默认元类是type类,类继承保持一致性意图比较明显,且 可以使用type中的方法
    • 元类可以使用一些类中特有的方法:__new____init__
  • 如果不确定是否需要用元类,就不应该使用

自定义元类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class UpperAttrMeta(type):
def __new__(cls, cls_name, bases, attrs):
upper_attrs=dict((name.upper(), val)
for name,val in attrs.items()
if not name.startswith('__')
);
return super(UpperAttrMeta,cls).__new__(
cls,
cls_name,
bases,
upper_attrs);
// 使用元类创建新类

class Foo(metaclass=UpperAttrMeta):
b=1;

使用自定义元类UppAttrMeta创建的类Foo中定义的__init____new__等函数无意义,因为该类不仅是通过元类创建,也是 通过元类初始化

  • Foo通过UpperAttrMeta创建,而UppAttrMeta本身没有 实现自定义__init__,默认继承于object

    因此Foo类的创建就有object的init完成 segmentfault.com/q/1010000004438156 这个是原话,不明白什么意思了

  • 但是如果元类仅仅是pass,如下:

    1
    2
    class MetaCls(type):
    pass;

    使用此自定义元类,类定义中的__init____new__有效

类创建

py2自定义元类

python创建类对象步骤

  • __metaclass__指定创建类使用的元类

    • 按照优先级:类定义内 > 祖先类内 > 模块内 > type, 查找__metaclass__,并使用其创建类对象,若前三者 均未定义__metaclass__,则使用type创建

    • 自定义元类就是为__metaclass__指定自定义值

    • python只是将创建类的参数传递给__metaclass__,并不 关心__metaclass__是否是一个

      • cls()返回一个类对象,是相当于调用cls.__new__
      • 所以可以指定__metaclass__为一个函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
		
def upper_attr(cls_name, bases, attrs):
upper_attrs=dict((name.upper(), val) for name,val in attrs.items());
return type(cls_name, bases, upper_attrs);

class Foo():
bar=1;
__metaclass__=upper_attr;

# 函数版本

class UpperAttrMeta(type):
def __new__(clsf, cls_name, bases, attrs):
upper_attrs=dict((name.upper(), val) for name,val in attrs.items());
return type(cls_name, bases, upper_attrs);

class Foo():
bar=1;
__metaclass__=UpperAttrMeta;

# 类版本1

class UpperAttrMeta(type):
def __new__(cls, cls_name, bases, attrs):
upper_attrs=dict((name.upper(), val) for name,val in attrs.items());
return type.__new__(cls, cls_name, bases, upper_attrs);

# 类版本2

class UpperAttrMeta(type):
def __new__(cls, cls_name, bases, attrs):
upper_attrs=dict((name.upper(), val) for name,val in attrs.items());
return super(UpperAttrMeta,cls).__new__(cls, cls_name, bases, upper_attrs);

# 类版本3

元类示例

缓存实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import weakref

class Cached(type):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__cache = weakref.WeakValueDictionary()

def __call__(self, *args):
if args in self.__cache:
return self.__cache[args]
else:
obj = super().__call__(*args)
self.__cache[args] = obj
return obj

class Spam(metaclass=Cached):
def __init__(self, name):
print("Creating Spam({!r})".format(name))
self.name = name

捕获类属性定义顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from collection import OrderedDict

class Typed:
_expected_type = type(None)
def __init__(self, name=None):
self._name = name

def __set__(self, instance, value):
if not instance(value, self_expected_type):
raise TypeError("expected" + str(self._expected_type))
instance.__dict__[self._name] = value

class Integer(Typed):
_expected_type = int

class Float(Typed):
_expected_type = float

class String(Typed):
_expected_type = str

class OrderedMate(type):
def __new__(cls, clsname, bases, clsdict):
d = dict(clsdict)
order = [ ]
for name, value in clsdict.items():
if isinstance(value, Typed):
value._name = name
order.append(name)
d["_order"] = order
return type.__new__(cls, clsname, bases, d)

@classmethod
def __prepare__(cls, clsname, bases):
# 此方法会在开始定义类、其父类时执行
# 必须返回一个映射对象,以便在类定义体中使用
return OrderedDict()

class Structure(metaclass=OrderedMeta):
def as_csv(self):
return ",".join(str(getattr(self, name)) for name in self._order)

class Stock(Structure):
name = String()
shares = Integer()
price = Float()

def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price

有可选参数元类

为了使元类支持关键字参数,必须在__prepare____new____init__方法中使用KEYWORDS_ONLY关键字参数

1
2
3
4
5
6
7
8
9
10
11
12
13
class MyMeta(type):
@classmethod
def __prepare__(cls, name, bases, *, debug=False, synchronize=False):
pass
return super().__prepare(naeme, bases)

def __new__(cls, name, bases, *, debug=False, synchronize=False):
pass
return super().__new__(cls, name, bases, ns)

def __init__(self, name, bases, ns, *, debug=False, synchronize=False):
pass
super().__init__(name, base, ns)
Author

UBeaRLy

Posted on

2019-03-31

Updated on

2019-03-31

Licensed under

Comments