Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/363.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xcode/7.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 如何通过手动填充_类_)单元格使super()工作?_Python_Metaprogramming_Python 3.x_Super - Fatal编程技术网

Python 如何通过手动填充_类_)单元格使super()工作?

Python 如何通过手动填充_类_)单元格使super()工作?,python,metaprogramming,python-3.x,super,Python,Metaprogramming,Python 3.x,Super,在Python3中,可以使用super()而不是super(MyClass,self),但这只适用于类内部定义的方法。如以下示例中所述,不起作用: def __init__(self): print('calling __init__') super().__init__() class C(object): __init__ = __init__ if __name__ == '__main__': c = C() 它失败是因为super()查找一个\uu

在Python3中,可以使用
super()
而不是
super(MyClass,self)
,但这只适用于类内部定义的方法。如以下示例中所述,不起作用:

def __init__(self):
    print('calling __init__')
    super().__init__()

class C(object):
    __init__ = __init__

if __name__ == '__main__':
    c = C()
它失败是因为
super()
查找一个
\uuuuuuu类
,该类在本例中未定义


在定义函数后,是否可以手动设置此单元格,还是不可能?

不幸的是,我不理解单元格在这种情况下是如何工作的(没有找到太多的文档)。我希望像这样的事情

__init__.__class_cell_thingy__ = C

当然,我只会在类赋值明确/唯一的情况下使用它(在我的例子中,向中的类添加方法的整个过程是自动化的,因此添加这样一行会很简单)。

也许吧,但是你会这样做吗?在这两种情况下,您都需要明确它是哪个类,因为隐式方法不起作用。也许您可以以某种方式显式设置单元格,但没有理由这样做。只需显式地传入参数

def __init__(self):
    print('calling __init__')
    super(self.__class__, self).__init__()

class C(object):
    __init__ = __init__

if __name__ == '__main__':
    c = C()
(如果你能直接通过实际的课程就更好了,比如:

def __init__(self):
    print('calling __init__')
    super(C, self).__init__()

class C(object):
    __init__ = __init__

if __name__ == '__main__':
    c = C()

但是如果你能做到这一点,你可以直接把
\uuu init\uuu
放在
C
上,所以假设你不能。你可以使用函数的字典

def f(self):
    super(f.owner_cls, self).f()
    print("B")

def add_to_class(cls, member, name=None):
    if hasattr(member, 'owner_cls'):
        raise ValueError("%r already added to class %r" % (member, member.owner_cls))
    member.owner_cls = cls
    if name is None:
        name = member.__name__
    setattr(cls, name, member)

class A:
     def f(self):
         print("A")

class B(A):
     pass

add_to_class(B, f)

B().f()

如果您不想在函数中硬编码成员名称的名称,您甚至可以添加另一个属性
member\u name

认真地说:您真的不想这样做

但是,Python的高级用户理解这一点很有用,所以我将对此进行解释

单元格和自由变量是创建闭包时指定的值。例如

def f():
    a = 1
    def func():
        print(a)
    return func
f
返回一个基于
func
的闭包,存储对
a
的引用。该引用存储在单元格中(实际上是在freevar中,但哪个由实现决定)。您可以检查:

myfunc = f()
# ('a',)
print(myfunc.__code__.co_freevars)
# (<cell at 0xb7abce84: int object at 0x82b1de0>,)
print(myfunc.__closure__)
(警告:这就是事情变得邪恶的地方。)

这些单元格在
func.\uuuuu closure\uuuuuu
中可见,但它是只读的;您不能更改它。更改它的唯一方法是创建一个新函数,这是使用
类型.FunctionType
构造函数完成的。但是,您的
\uuuuu init\uuuuuuu
函数根本没有
\uuuuuuu类
自由变量,因此我们需要添加一个。这意味着我们还必须创建一个新的代码对象

下面的代码就是这样做的。为了演示的目的,我添加了一个基类
B
。这段代码做了一些假设,例如
\uuuu init\uuuu
还没有一个名为
\uu class\uuuu
的自由变量

这里还有另一个问题:似乎没有单元格类型的构造函数。为了解决这个问题,创建了一个虚拟函数
C.dummy
,其中包含我们需要的单元格变量

import types

class B(object):
    def __init__(self):
        print("base")

class C(B):
    def dummy(self): __class__

def __init__(self):
    print('calling __init__')
    super().__init__()

def MakeCodeObjectWithClass(c):
    """
    Return a copy of the code object c, with __class__ added to the end
    of co_freevars.
    """
    return types.CodeType(c.co_argcount, c.co_kwonlyargcount, c.co_nlocals,
            c.co_stacksize, c.co_flags, c.co_code, c.co_consts, c.co_names,
            c.co_varnames, c.co_filename, c.co_name, c.co_firstlineno,
            c.co_lnotab, c.co_freevars + ('__class__',), c.co_cellvars)

new_code = MakeCodeObjectWithClass(__init__.__code__)
old_closure = __init__.__closure__ or ()
C.__init__ = types.FunctionType(new_code, globals(), __init__.__name__,
    __init__.__defaults__, old_closure + (C.dummy.__closure__[0],))

if __name__ == '__main__':
    c = C()

“是否可以手动设置此单元格”?当您尝试此操作时,发生了什么?但是在定义函数后,我如何才能访问此单元格?
\uuuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuhod多次。你不能正确地使用
super(…)
。如果你在运行时修改一个类,你可以简单地对它进行硬编码。@nikow:嗯,调用super()在类自己的
\uuuuu init\uuuuu
中,然后可能用一个修饰符来包装该init。@s.Lott:在我的示例中使用
\uuuuuu init\uuuu
方法并不重要在我看来,我的问题相当具体,我得到了一个很好的答案。所以我真的不明白为什么我要为这个问题辩护。谢谢你的回答,但你在这里提出的建议是非常错误的。你不能用
self.\uu class\uuuuuuuu
super
,就像最近在这里解释的那样:@nikow:好吧,如果你要去的话如果子类也使用super(),那么要将其子类化,您可能会遇到问题。因此,您希望对许多不同的类使用相同的
\uuuu init\uuuu
(因为否则您不会在类之外定义它)你不知道哪些类,也不知道这些类是否或如何子类化?在这种情况下,我会说你解决问题的方法是错误的。我可以推荐一个类装饰器,或者一个带有适配器的组件架构吗?@Lennart:添加的函数是按照AOP的想法在别处定义的,这在我们的项目中非常有效t、 在实际代码中,这些“方面”是在运行时激活/停用的,因此使用decorator类并不是一个真正的选项。我只是希望能够启用简化的
super()
调用,毕竟它们是出于某种原因被添加到Python 3中的。@nikow:当然,我理解。只是调用super()从您案例中添加的方法来看,这似乎是一个坏主意。因此,建议使用适配器(实现使代码在其他地方定义的相同功能)或者decorators。由于它是运行时,deocrators是不可能的,但适配器不是。您应该真正了解Zope组件体系结构,它是面向方面的,即使它不喜欢吹嘘它。:)但对于正在进行的项目来说可能太晚了,但是你可能会有想法。你永远不应该使用
self.\uu class\uu
super()
,因为现在如果你将
C
子类化,你会得到一个无限循环。传入显式类对象,或为
\uuuuuu class\uuuuu
提供闭包<代码>self.\uuuu类\uuuu
是错误的引用。这会起作用,但我不确定我是否更喜欢它,而不是编写类的显式解决方案。毕竟我知道该方法将属于哪个类,我只想从更方便的Python3
super()
中获益
import types

class B(object):
    def __init__(self):
        print("base")

class C(B):
    def dummy(self): __class__

def __init__(self):
    print('calling __init__')
    super().__init__()

def MakeCodeObjectWithClass(c):
    """
    Return a copy of the code object c, with __class__ added to the end
    of co_freevars.
    """
    return types.CodeType(c.co_argcount, c.co_kwonlyargcount, c.co_nlocals,
            c.co_stacksize, c.co_flags, c.co_code, c.co_consts, c.co_names,
            c.co_varnames, c.co_filename, c.co_name, c.co_firstlineno,
            c.co_lnotab, c.co_freevars + ('__class__',), c.co_cellvars)

new_code = MakeCodeObjectWithClass(__init__.__code__)
old_closure = __init__.__closure__ or ()
C.__init__ = types.FunctionType(new_code, globals(), __init__.__name__,
    __init__.__defaults__, old_closure + (C.dummy.__closure__[0],))

if __name__ == '__main__':
    c = C()