[英]Python: How do I dynamically alter methods of dict and list objects?
这是我想要做的模型:
alist = [1,2,3,4,5] # create a vanilla python list object
replacef (alist) # replace __setitem__, extend,... with custom functions
alist[0]=2 # now the custom __setitem__ is called
这适用于DSL项目,其语法应尽可能接近普通python,因此子类化列表并使用户调用类似alist = MyList(1,2,3,4,5)是不可取的。 此外,由于DSL需要与其他库共存,全局更改列表和字典不是一个选项...
我已经尝试创建instancemethods并直接在对象上设置它们,如alist.append = myFunc,但Python说这些属性是只读的。 似乎也不允许更改__class__
属性。
我想在Python中尝试做什么?
更新 :这里有一些关于对象的子类可能的一些发现:
鉴于:
class y(object):
def __init__(self,a,b,c):
self.a = a
self.b = b
self.c = c
def f(self):
print self
print self.a
print self.b
print self.c
class x(object):
def __init__(self,a,b,c):
self.a = a
self.b = b
self.c = c
def f(self):
print "x.f()"
>>> objy = y(1,2,3)
>>> objx = x(4,5,6)
>>> objy.f()
<__main__.y object at 0x02612650>
1
2
3
>>> objx.f()
x.f()
可以像这样改变objx的类:
>>> objx.__class__ = y
>>> objx.f()
<__main__.y object at 0x02612D90>
4
5
6
此外,可以动态地动态添加/更改对象方法,就像在javascript中一样:
>>> def g(self,p):
print self
print p
>>> import new
>>> objy.g = new.instancemethod(g,objy,y)
>>> objy.g(42)
<__main__.y object at 0x02612650>
42
但是,这两种方法都会失败,其中包含在C中实现的对象,如dict和list:
>>> def mypop(self):
print "mypop"
list.mypop(self)
>>> alist.pop = new.instancemethod(mypop,alist,list)
AttributeError: 'list' object attribute 'pop' is read-only
>>> x = [1,2,3,4,5]
>>> x.__class__ = mylist
TypeError: __class__ assignment: only for heap types
建议使用alist = replacef(alist)之类的方法在这里不起作用,因为可以从__setattribute__
调用中调用__setattribute__
如下所示:
alist = [1,2,3,4,5]
aDSLObject.items = alist # __setattribute__ calls replacef on alist
alist[0] = ....
因此,虽然确实可以动态地改变对象方法,但似乎不可能改变用C实现的对象的行为 - 或者我错过了什么?
也许你可以在replaceref
函数里面做“alist = MyList(1,2,3,4,5)”的事情?
def replacef(l):
return MyList(l) # Return instance of list subclass that has custom __setitem__
alist = [1,2,3,4,5]
alist = replaceref(alist)
这样,用户在定义列表时仍会使用标准列表语法,但会在replaceref
调用后获得新的setitem 。
“明确比隐含更好。” 您应该记录您的用户需要使用MyList()
而不是list()
。 从长远来看,您和您的用户将会更加快乐。
顺便说一句,Ruby允许你想要的东西。 使用Ruby,您可以打开全局对象并添加新行为。 我发现这很可怕,Ruby运行速度比Python慢,所以我实际上并没有敦促你切换到Ruby。
因此,提供MyList()
,并提供一种获取现有列表并将其包装在MyList()
。
您可以编写MyList()
来获取一堆参数,并非常方便地创建一个列表:
class MyList(object):
def __init__(self, *args):
self.lst = args
# add other methods to MyList() here
然后你可以使用MyList(1, 2, 3, 4)
调用它,并且实例将有一个名为lst的成员,其值为: [1, 2, 3, 4]
但是现在,如果你想从列表中创建一个MyList
实例,你是如何做到的? 如果你这样做:
new_list = [1, 3, 5]
x = MyList(new_list)
然后你只需将x设置为: [[1, 3, 5]]
所以我建议你让MyList()
只需要一个list参数并保存它:
def ensure_list(seq):
try:
seq[0]
return seq
except TypeError:
return list(seq)
class MyList(object):
def __init__(self, seq):
self.lst = ensure_list(seq)
# add other methods to MyList() here
我刚编辑了这个答案。 最初,我调用了list()
,现在我调用了ensure_list()
。 ensure_list()
检查是否可以索引其参数; 如果可以的话,它既可以是列表,也可以像列表一样,并且不会更改。 如果你不能索引它,那么ensure_list()
调用list(seq)
来尝试将它变成一个列表。 这将与迭代器和生成器一起使用,强制它们扩展到列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.