如何派生内置不可变类型并修改其实例化行为
我们想自定义一种新类型的元组,对于传入的可迭代对象,我们只保留其中int类型且值大于0的元素,例如:
IntTuple([2,-2,‘jr’,[‘x’,‘y’],4]) => (2,4)
如何继承内置tuple 实现IntTuple?
如果直接在init中进行修改
class IntTuple(tuple):
def __init__(self, iterable):
for i in iterable:
if isinstance(i, int) and i > 0:
super().__init__(i)
int_t = IntTuple([2, -2, 'jr', ['x', 'y'], 4])
print(int_t) # TypeError: object.__init__() takes no parameters
打印self
class IntTuple(tuple):
def __init__(self, iterable):
# for i in iterable:
# if isinstance(i, int) and i > 0:
# super().__init__(i)
print(self)
int_t = IntTuple([2, -2, 'jr', ['x', 'y'], 4])
print(int_t)
# (2, -2, 'jr', ['x', 'y'], 4)
# (2, -2, 'jr', ['x', 'y'], 4)
self 是谁创建的呢? 接下来研究对象中的"new"方法
class A(object):
def __new__(cls, *args, **kwargs):
print('__new__...', cls, args)
return object().__new__(cls)
def __init__(self, *args):
print('__init__....')
a = A(1, 2)
__new__... <class '__main__.A'> (1, 2)
__init__....
可见先执行new方法,在执行的init方法,且必须要返回object().new(cls),init方法才可以执行。所以真正创建对象的是new方法 , cls就是创建的类
所以a = A(1,2)在python中执行顺序为
a = A.new(A, 1, 2),A.init(a, 1, 2)
接下来举个例子说明一下列表与元组的创建顺序
列表
l = list('abc')
print(l) # ['a', 'b', 'c']
l = list.__new__(list, 'abc')
print(l) # []
list.__init__(l, 'abc')
print(l) # ['a', 'b', 'c']
元组
t = tuple('def')
print(t) # ('d', 'e', 'f')
t = tuple.__new__(tuple, 'def')
print(t) # ('d', 'e', 'f')
所以说明在new方法中元组已经被创建好,在init方法中在进行修改就会出错,所以要在new方法进行修改
元组
class IntTuple(tuple):
def __new__(cls, iterable):
# 生成器
f = (i for i in iterable if isinstance(i, int) and i > 0)
return super().__new__(cls, f) # 这里也可以用IntTuple代替cls不过会使代码变为硬编码,不利于修改
int_t = IntTuple([2, -2, 'jr', ['x', 'y'], 4])
print(int_t) # (2, 4)
列表
class IntList(list):
def __new__(cls, *args):
print('new', cls, args)
return super().__new__(cls, args)
def __init__(self, arg):
f = [i for i in arg if isinstance(i, int) and i > 0]
print(f)
a = IntList([1, 2, 3, -1, -2, -3])
# new <class '__main__.IntList'> ([1, 2, 3, -1, -2, -3],)
# [1, 2, 3]
l = IntList.__new__(IntList, (1, 2))
IntList.__init__(l, (1, 2))
# new <class '__main__.IntList'> ((1, 2),)
# [1, 2]