python中的函数可以表现得像一个类吗?

时间:2014-08-06 09:11:19

标签: python function class

在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__

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

修改

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

getResult.__dict__

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

function addOneFunc at <0xXXXXXXXXX>

2 个答案:

答案 0 :(得分:3)

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

def foo(bar):
    return bar

大致相当于

class Foo(object):

    def __call__(self, bar):
        return bar

foo = Foo()

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


例如,可以使用向函数添加属性来实现memoization装饰器,它会缓存以前对函数的调用:

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

请注意,此属性也可以在内部函数中访问,但在 函数之后才能定义


你可以这样做:

>>> 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

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

但请注意,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'

另一个问题是正好你正在尝试做什么:

>>> 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>

答案 1 :(得分:2)

不确定以下是否是您正在考虑的问题,但您可以这样做:

>>> def f(x):
...   print(x)
... 
>>> f.a = 1
>>> f.a
1
>>> f(54)
54
>>> f.a = f
>>> f
<function f at 0x7fb03579b320>
>>> f.a
<function f at 0x7fb03579b320>
>>> f.a(2)
2

因此,您可以为函数指定属性,这些属性可以是变量或函数(请注意,为简单起见,选择了f.a = f;当然,您可以将f.a指定给任何函数。)

如果你想访问函数内部的局部变量,我认为它更难,你可能确实需要恢复内省。以下示例使用func_code属性:

>>> def f(x):
...   a = 1
...   return x * a
... 
>>> f.func_code.co_nlocals
2
>>> f.func_code.co_varnames
('x', 'a')
>>> f.func_code.co_consts
(None, 1)