Python:如何动态地改变dict和list对象的方法?

2024-04-20 13:14:48 发布

您现在位置:Python中文网/ 问答频道 /正文

下面是我想做的一个模型:

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,因此子类化list并让用户调用alist=MyList(1,2,3,4,5)是不可取的。另外,由于DSL需要与其他库共存,全局更改list和dict不是一个选项。。。在

我尝试过创建instancemethods并将它们直接设置在对象上,比如列表.append=myFunc,但Python说这些属性是只读的。似乎也不允许更改__class__属性。在

我想在Python中做的事情是可能的吗?在

更新:下面是一些关于object的子类可能的发现:

给予:

^{pr2}$

可以像这样动态更改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)的方法在这里行不通,因为replacef可以从__setattribute__调用中调用,如下所示:

alist = [1,2,3,4,5]
aDSLObject.items = alist #  __setattribute__ calls replacef on alist
alist[0] = ....

因此,虽然可以动态地更改对象方法,但似乎不可能更改用C实现的对象的行为,或者我遗漏了什么?在


Tags: 对象方法selfnewobject动态listclass
2条回答

“显式比隐式好。”您应该只记录用户需要使用MyList()而不是{}。从长远来看,你和你的用户会更快乐。在

顺便说一句,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实例,该如何实现呢?如果您这样做:

^{pr2}$

那么您只需将x设置为:[[1, 3, 5]]

因此,我建议您使MyList()只需获取一个列表参数并保存它:

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)来尝试将其转换为一个列表。这将使用迭代器和生成器,迫使它们展开到列表中。在

也许您可以在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)

{/strong>当一个标准的调用后,用户仍然会使用一个新的列表。在

相关问题 更多 >