python 中的函数可以像类一样运行吗?

Joh*_*ank 3 python class function

在python中,函数是第一类对象。可以调用一个类。所以你可以用一个类替换一个函数。但是你能让一个函数表现得像一个类吗?您可以在函数中添加和删除属性或调用内部函数(然后调用方法)吗?

我找到了一种通过代码检查来做到这一点的方法。

import inspect

class AddOne(object):
    """class definition"""
    def __init__(self, num):
        self.num = num

    def getResult(self):
        """
        class method
        """
        def addOneFunc(num):
            "inner function"
            return num + 1

        return addOneFunc(self.num);

if __name__ == '__main__':
    two = AddOne(1);
    two_src = '\n'.join([line[4:] for line in inspect.getsource(AddOne.getResult).split('\n')])
    one_src = '\n'.join([line[4:] for line in two_src.split('\n')
                    if line[:4] == '    ' and line[4:8] == '    ' or line[4:8] == 'def '])
    one_co = compile(one_src, '<string>', 'exec')
    exec one_co
    print addOneFunc(5)
    print addOneFunc.__doc__
Run Code Online (Sandbox Code Playgroud)

但是有没有办法以更直接的方式访问类中定义的局部变量和函数?

编辑

问题是如何访问python的内部结构以获得更好的理解。当然,我不会在正常编程中这样做。当我们讨论 Python 中的私有变量时,问题就出现了。我的观点是这违背了语言的哲学。所以有人想出了上面的例子。目前看来他是对的。如果没有检查模块,您将无法访问函数内部的函数,从而将此函数设为私有。使用 co_varnames 我们非常接近,因为我们已经有了函数的名称。但是保存名称的命名空间字典在哪里。如果您尝试使用

getResult.__dict__
Run Code Online (Sandbox Code Playgroud)

它是空的。我喜欢的是来自 python 的答案,例如

function addOneFunc at <0xXXXXXXXXX>
Run Code Online (Sandbox Code Playgroud)

jon*_*rpe 8

您可以将函数视为仅实现 的类的实例__call__,即

def foo(bar):
    return bar
Run Code Online (Sandbox Code Playgroud)

大致相当于

class Foo(object):

    def __call__(self, bar):
        return bar

foo = Foo()
Run Code Online (Sandbox Code Playgroud)

函数实例有一个__dict__属性,因此您可以自由地向它们添加新属性。


例如,可以使用向函数添加属性来实现记忆装饰器,该装饰器缓存先前对函数的调用:

def memo(f):
    @functools.wraps(f)
    def func(*args):
        if args not in func.cache: # access attribute
            func.cache[args] = f(*args)
        return func.cache[args]
    func.cache = {} # add attribute
    return func
Run Code Online (Sandbox Code Playgroud)

请注意,此属性也可以函数内部访问,尽管它只能在函数之后才能定义。


因此,您可以执行以下操作:

>>> def foo(baz):
        def multiply(x, n):
                return x * n
        return multiply(foo.bar(baz), foo.n)

>>> def bar(baz):
    return baz

>>> foo.bar = bar
>>> foo.n = 2
>>> foo('baz')
'bazbaz'
>>> foo.bar = len
>>> foo('baz')
6
Run Code Online (Sandbox Code Playgroud)

(虽然可能没有人会感谢你!)

但是请注意,multiply未成为 的属性的foo不能从函数外部访问:

>>> foo.multiply(1, 2)

Traceback (most recent call last):
  File "<pyshell#20>", line 1, in <module>
    foo.multiply(1, 2)
AttributeError: 'function' object has no attribute 'multiply'
Run Code Online (Sandbox Code Playgroud)

另一个问题正是您想要做的:

>>> import inspect
>>> import new
>>> class AddOne(object):
    """Class definition."""

    def __init__(self, num):
        self.num = num

    def getResult(self):
        """Class method."""
        def addOneFunc(num):
            "inner function"
            return num + 1    
        return addOneFunc(self.num)

>>> two = AddOne(1)
>>> for c in two.getResult.func_code.co_consts:
    if inspect.iscode(c):
        print new.function(c, globals())


<function addOneFunc at 0x0321E930>
Run Code Online (Sandbox Code Playgroud)