如何在类外使用函数作为类内的属性?

时间:2019-04-06 21:20:31

标签: python python-3.x abc

我遇到一些问题。我们如何在可以在类属性中使用的函数之外定义函数?另外,如何将self参数插入函数签名?我想像这样可视化:

>>> def a(self, x):   #I thought maybe class will give "self" to this property function
...     print(self)
... 
>>> class aa:
...     def __init__(self):
...         pass
...     @a
...     def p():
...         print('in it')
... 
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 4, in aa
    TypeError: a() missing 1 required positional argument: 'x'

我想在外部定义一个函数,但要在一个类内部使用。就像类的方法作为属性一样。我该怎么办?

2 个答案:

答案 0 :(得分:0)

如果您想创建一个使用在类外部定义的函数的属性,则将是这样的:

def myfunc(self):
    return self._p

class Foo:
    def __init__(self, p):
        self._p = p
    p = property(myfunc)

f = Foo("Alpha")
f.p # gives "Alpha"

property接受一个函数作为其(第一个)参数。该函数应具有self作为参数,并应返回您希望属性评估的值。

答案 1 :(得分:0)

目前还不清楚您要让类外函数做什么。有很多可能性,但是您可能还不知道要向我们描述的术语。

这是我认为最有可能的三个:

  1. 您可能希望您的功能成为装饰器。这意味着您可以将@decorator语法的方法应用于其他函数,包括类中的方法。

    为此,需要编写函数以接受函数对象作为其唯一参数。它返回的内容将替换将被调用的函数或方法,因此通常您希望返回一个可调用对象,但是可以像property一样返回一个描述符。尝试这样的事情:

    def decorator(func):
        def wrapper(self, *args, **kwargs):
            print("in the wrapper")
            result = func(self, *args, **kwargs)
            print("wrapper is done")
            return result
        return wrapper
    
    class Foo:
        @decorator
        def foo(self, x):
            print("in foo(), x is", x)
    
    f = Foo()
    f.foo(1) # prints three messages
    

    调用foo方法时,实际上是要调用装饰器应用于原始方法(wrapper)后返回的func方法。由于我们编写包装程序的方式,它将调用func,因此原始方法也将打印出其消息。

  2. 您可能想使用property描述符类型)来调用类外函数。这种使用property的方法比在方法上将其作为装饰器使用的方法要少得多,但这并非不可能。您甚至可以具有两种不同的功能,一种是在请求属性时调用,另一种是在设置属性时调用(但我将仅使用getter进行演示):

    def getter(obj):
        print("in the getter")
        return 1
    
    class Foo2:
        foo = property(getter)
    
    f2 = Foo2()
    print(f2.foo) # prints a message from the getter function first, then prints 1
    

    请注意,以这种方式构建属性时,不能使用@decorator语法。那只是函数定义之前的合法语法,我们没有在类内部定义任何函数。

  3. 您可能只想将在类外部定义的函数复制到其中,而无需任何修饰符或属性。这是最简单的操作,只是一个简单的任务:

    def func(self, x):
        print("x is", x)
    
    class Foo3:
        method = func  # just assign the global to a name in the class body
        func = func    # you can even use the same name if you don't mind confusing people
    
    f3 = Foo3()
    f3.method(1)
    f3.func(2)