我正在编写一个自定义类,该类通过添加一些新功能(如改组,加法,乘法等)来扩展默认的python列表。代码是这样的:
class xlist(list):
def __init__(self, original_list: list):
self._olist = original_list
def sumall(self) -> int:
sum = 0
for e in self._olist:
sum += e
return sum
...
但是在进行一些计算时,我需要获取xlist
实例的类型。我想做这样的事情:
>>> from xlist import xlist
>>> x = xlist([1, 2, 3])
>>> type(x)
[执行此操作时,我得到<class 'xlist.xlist'>
,但我希望它返回list
。
我对元类似乎有点困惑,它似乎能够解决问题。
有帮助吗?
如果您确实创建了type(x)
,为什么期望list
返回xlist
?您的xlist
继承自list
,因此每个xlist
对象是 list
的一个实例,因为它继承自它的所有行为(并通过添加一些新功能进行扩展)。
注意:
x = xlist([1, 2, 3])
isinstance(x, list)
返回True
。您可能还想看看Difference between type()
and isinstance()
Python用两种方法检查对象的类-一种是调用type()
,另一种是检查isinstance()
插槽。大多数情况下,两者都返回相同的内容,但是可以修改类(例如,通过自定义元类的属性访问),以便type
会“撒谎”,而使用__class__
的Python代码将获得“假”信息。 >
但是,在下面,__class__
对象中的“ true” myobject.__class__
插槽将始终保留对实型的引用-这不能被伪造。任何C扩展,甚至可能是几个Python扩展,以及返回__class__
本身都会看到真实的类。
更改此插槽的内容实际上changes
您的实例的类。从纯Python带有简单的type
属性是可行的-但此分配上有防护措施以确保仅在具有兼容内存布局的类型之间完成此分配。强制将其更改为不兼容的类型(通过扩展名或ctypes)将使您的Python运行时成为segfault。话虽如此,没有理由向班级用户撒谎您的班级-他们应该能够“看到”持有的对象是type(myobject)
而不是=
,并且[由于继承,C0]也是xlist
对象。伪造此信息将是一个相当糟糕的做法。另一方面,在Python stdlib本身中,很少有调用要求底层对象确实是list
并且不接受子类型(众所周知,Python的xlist
序列化)。该调用具有本机代码路径,不会因自定义对list
的访问而被欺骗。但是,同一调用还具有仅Python的代码路径,该代码路径是通过设置一些可选参数(例如,在调用中传递ident = 4)触发的。如果那是您想要实现的(愚弄一些需要严格列表的代码),那么您就必须搞砸了,如果是Python代码,那是可行的。在list
的特定情况下,最好伪造编码器以使用不严格的检查,而不是伪造您的对象-因为我认为那里的代码使用json.dumps
进行检查。
因此,以上所述,伪造__class__
的返回的“元类技巧”可以很简单:
json.dump