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

Sre*_*ram 3 python dynamic-languages python-3.x

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

In [1]: def somefnc(a, b):
...:     return a+b
...: 
Run Code Online (Sandbox Code Playgroud)

我首先尝试将__call__变量分配给以None消除函数的“可调用性质”。但正如您所看到的,__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]: 
Run Code Online (Sandbox Code Playgroud)

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

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

Eli*_*igo 5

在 Python 中,函数是类的实例function。因此,我将为您提供有关任何类和实例的一般答案。

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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

当通过名称访问时,所有方法首先通过实例访问。差异是由于不同的搜索机制造成的。当您按名称访问方法/属性时,__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
Run Code Online (Sandbox Code Playgroud)

LOAD_ATTR正如您所看到的,第一种情况没有。该[]运算符被汇编为特殊的虚拟机指令BINARY_SUBSCR