Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何更改活动对象';是什么行为?_Python_Python 3.x_Class_Inheritance_Metaclass - Fatal编程技术网

Python 如何更改活动对象';是什么行为?

Python 如何更改活动对象';是什么行为?,python,python-3.x,class,inheritance,metaclass,Python,Python 3.x,Class,Inheritance,Metaclass,我想更改活动python对象的isinstance的行为 一种解决方案是创建一个简单的包装器,如下所示,但我不喜欢它: class Widget: def __init__(self, obj): self.inner_self = obj lizard = ['head', 'nose', 'tail'] wlizard = Widget(lizard) assert(isinstance(wlizard, Widget)) # no assertion error

我想更改活动python对象的
isinstance
的行为

一种解决方案是创建一个简单的包装器,如下所示,但我不喜欢它:

class Widget:
    def __init__(self, obj):
        self.inner_self = obj

lizard = ['head', 'nose', 'tail']
wlizard = Widget(lizard)
assert(isinstance(wlizard, Widget)) # no assertion error thrown 
我不喜欢这个特殊的包装器,因为我们必须从
wlizard
中提取
lizard
,然后才能再次使用
lizard

try:
    wlizard[0]
except:
    print('sorry, wlizard doesn\'t behave like a lizard')

lizard = wlizard.inner_self
print(lizard[0]) # works fine
我真正想要的是
wlizard
的行为与蜥蜴完全一样,除了
isinstance
wlizard
返回
True
,为
lizard
返回false之外

以下是一些可行的方法,但也有一些缺点:

class Widget:
    pass

def MakeAWidget(obj):

    class Blah(type(obj), Widget):
        pass
        # inherits type(obj)'s __init__ method

    wobj = Blah(obj)  # calls type(obj)'s copy constructor
    return wobj
一个问题是,只有当
type(obj)
\uuu init\uuu()
方法接受的不仅仅是
self
时,这种方法才有效;特别是,
\uuuuu init\uuuu
可以采用
类型(obj)
的实例,当采用该实例时,它将
obj
的属性复制到
self
中。我想要一些即使
obj
没有复制构造函数也能工作的东西。类似以下内容可能会强制存在副本构造函数:

import copy
class Blah(type(obj), Widget):
    def __init__(*args, **kwargs):
        if isinstance(args[0], type(obj)):
            self = copy.deepcopy(args[0])
            return self
        return super(type(self), self).__init__(*args, **kwargs)
但是,我宁愿不复制对象,只在适当的位置修改它。 类似于以下内容可能是可能的,但我不确定什么是
\uuu BLAH\uuu

obj = ['apple', 'pear', 'banana']
assert(not isinstance(obj, Widget)) # no error thrown    
obj.__BLAH__.append('Widget')
assert(isinstance(obj, Widget))  # no error thrown

我想这是你想要的东西。
wrap()
函数动态创建一个从传递给它的
obj
参数的类派生的类,然后返回从该类创建的类的实例。这假设
obj
类支持复制构造(从同一类或派生类的实例初始化)


这听起来像是你为一些根本问题选择了一个糟糕的解决方案,如果不这样做,这个问题会得到更好的解决。为什么要用这种方式更改对象?为什么您关心对象如何响应
isinstance
,而不是它们所支持的行为?蜥蜴是什么类型的Python对象?@user2357112我创建了一个包装器,它允许您通过
\uuuuu getattribute\uuuu
访问对象的
\uu getitem\uuuuuu>方法
wrap_obj.key==obj[key]
但是,我想知道返回的值是来自
\uuu getitem\uuuu
还是属于
obj
的属性。一种解决方案似乎是对返回值调用
isinstance
,查看它是什么。@Blender在我的示例中,
lizard
是一个
列表。然而,在实际应用中,我们不知道什么是蜥蜴。解决方案需要足够通用,以处理大多数类型的对象。@ToothickAnemone:既然您可以控制底层类,那么您要解决的确切问题是什么?这似乎是一个糟糕的方法。
def wrap(obj):
    class MetaClass(type):
        def __new__(mcls, classname, bases, classdict):
            wrapped_classname = '_%s_%s' % ('Wrapped', type(obj).__name__)
            return type.__new__(mcls, wrapped_classname, (type(obj),)+bases, classdict)

    class Wrapped(metaclass=MetaClass):
        pass

    return Wrapped(obj)

lizard = ['head', 'nose', 'tail']
wlizard = wrap(lizard)
print(type(wlizard).__name__)     # -> _Wrapped_list
print(isinstance(wlizard, list))  # -> True

try:
    wlizard[0]
except Exception as exc:
    print(exc)
    print("sorry, wlizard doesn't behave like lizard")
else:
    print('wlizard[0] worked')