是否可以将 python 函数转换为 class?

Is it possible to convert a python function into a class?

我是 Python 的新手,来自 C++ 背景,这是我第一次看到一种只包含对象的语言。我刚刚了解到 class 和函数也只是对象。那么,有没有办法将以下函数转换为 class?

In [1]: def somefnc(a, b):
...:     return a+b
...: 

我首先尝试将 __call__ 变量分配给 None 以从函数中删除 "callable nature"。但是正如您所看到的,__call__ 已成功替换为 None 但这并没有导致函数在调用时停止添加数字,尽管 somefnc.__call__(1,3) 正在工作在将 somefnc.__call__ 分配给 None

之前
In [2]: somefnc.__dict__ 
Out[2]: {}

In [3]: somefnc.__call__
Out[3]: <method-wrapper '__call__' of function object at 0x7f282e8ff7b8>

In [4]: somefnc.__call__ = None

In [5]: x = somefnc(1, 2)

In [6]: print(x)
3

In [7]: somefnc.__call__

In [8]: print(somefnc.__call__(1, 2))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
ipython-input-8-407663da97ca     
in <module>()
----> 1 print(somefnc.__call__(1, 2))

TypeError: 'NoneType' object is not callable

In [9]: print (somefnc(1,2))
3

In [10]: 

我不是为了开发目的而这样做,所以声称这是一种不好的做法没有任何意义。我只是想很好地理解 Python。当然,出于开发目的,我宁愿创建一个 class 而不是将一个函数转换为一个函数!

在剥夺函数将两个数字相加的能力后,我正在考虑通过修改 somefun.__dict__ 将有效函数分配给属性 somefnc.__init__ 和一些成员,以将其转换为 class。

在 Python 函数中是 function class 的实例。所以我会给你一个关于任何 class 和实例的一般性答案。

In [10]: class Test:
    ...:     def __getitem__(self, i):
    ...:         return i
    ...:     

In [11]: t = Test()

In [12]: t[0]
Out[12]: 0

In [13]: t.__getitem__(0)
Out[13]: 0

In [14]: t.__getitem__ = None

In [15]: t[0]
Out[15]: 0

In [16]: t.__getitem__(0)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-16-c72f91d2bfbc> in <module>()
----> 1 t.__getitem__(0)

TypeError: 'NoneType' object is not callable

在 Python 中,所有特殊方法(前缀和后缀中带有双下划线的方法)在通过运算符触发时从 class 访问,而不是从实例访问。

In [17]: class Test2:
    ...:     def test(self, i):
    ...:         return i
    ...:     

In [18]: t = Test2()

In [19]: t.test(1)
Out[19]: 1

In [20]: t.test = None

In [20]: t.test(1)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-22-261b43cb55fe> in <module>()
----> 1 t.test(1)

TypeError: 'NoneType' object is not callable

当按名称访问时,首先通过实例访问所有方法。差异是由于不同的搜索机制。当您按名称访问 method/attribute 时,您会调用 __getattribute__,默认情况下它将首先在实例的命名空间中进行搜索。当您通过运算符触发方法时,不会调用 __getattribute__。你可以在反汇编中看到它。

In [22] import dis

In [23]: def test():
    ...:     return Test()[0]
    ...:     

In [24]: dis.dis(test)
  2           0 LOAD_GLOBAL              0 (Test)
              3 CALL_FUNCTION            0 (0 positional, 0 keyword pair)
              6 LOAD_CONST               1 (0)
              9 BINARY_SUBSCR
             10 RETURN_VALUE

In [25]: def test2():
    ...:     return Test().__getitem__(0)
    ...: 

In [26]: dis.dis(test2)
  2           0 LOAD_GLOBAL              0 (Test)
              3 CALL_FUNCTION            0 (0 positional, 0 keyword pair)
              6 LOAD_ATTR                1 (__getitem__)
              9 LOAD_CONST               1 (0)
             12 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             15 RETURN_VALUE

如您所见,第一种情况下没有LOAD_ATTR[] 运算符被组装成一个特殊的虚拟机指令 BINARY_SUBSCR