在 Python 类声明中调用方法的最佳方式?

发布于 2024-07-09 08:00:20 字数 1588 浏览 6 评论 0原文

假设我正在声明一个类 C,其中一些声明非常相似。 我想使用函数 f 来减少这些声明的代码重复。 可以像往常一样声明和使用 f

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     w = f(42)
... 
>>> C.v
'<9>'
>>> C.w
'<42>'
>>> C.f(4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method f() must be called with C instance as first argument (got int instance instead)

哎呀! 我无意中将 f 暴露给了外界,但它不需要 self 参数(并且出于明显的原因不能)。 一种可能是在使用函数后删除该函数:

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     del f
... 
>>> C.v
'<9>'
>>> C.f
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'C' has no attribute 'f'

但是如果我想在声明之后再次使用 f 该怎么办? 删除该功能是不行的。 我可以将其设置为“私有”(即,在其名称中添加前缀 __)并对其进行 @staticmethod 处理,但通过调用 staticmethod 对象异常通道变得非常时髦:

>>> class C(object):
...     @staticmethod
...     def __f(num):
...             return '<' + str(num) + '>'
...     v = __f.__get__(1)(9)   # argument to __get__ is ignored...
... 
>>> C.v
'<9>'

我必须使用上面的疯狂方法,因为作为描述符的 staticmethod 对象本身不可调用。 我需要先恢复由 staticmethod 对象包装的函数,然后才能调用它。

必须有更好的方法来做到这一点。 如何在类中干净地声明一个函数,在声明期间使用它,以及稍后在类中使用它? 我应该这样做吗?

Say I am declaring a class C and a few of the declarations are very similar. I'd like to use a function f to reduce code repetition for these declarations. It's possible to just declare and use f as usual:

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     w = f(42)
... 
>>> C.v
'<9>'
>>> C.w
'<42>'
>>> C.f(4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method f() must be called with C instance as first argument (got int instance instead)

Oops! I've inadvertently exposed f to the outside world, but it doesn't take a self argument (and can't for obvious reasons). One possibility would be to del the function after I use it:

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     del f
... 
>>> C.v
'<9>'
>>> C.f
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'C' has no attribute 'f'

But what if I want to use f again later, after the declaration? It won't do to delete the function. I could make it "private" (i.e., prefix its name with __) and give it the @staticmethod treatment, but invoking staticmethod objects through abnormal channels gets very funky:

>>> class C(object):
...     @staticmethod
...     def __f(num):
...             return '<' + str(num) + '>'
...     v = __f.__get__(1)(9)   # argument to __get__ is ignored...
... 
>>> C.v
'<9>'

I have to use the above craziness because staticmethod objects, which are descriptors, are not themselves callable. I need to recover the function wrapped by the staticmethod object before I can call it.

There has got to be a better way to do this. How can I cleanly declare a function in a class, use it during its declaration, and also use it later from within the class? Should I even be doing this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

天生の放荡 2024-07-16 08:00:20

很简单,解决方案是 f 不需要是该类的成员。 我假设您的思维过程已经通过了 Javaish 语言过滤器,导致了心理障碍。 它有点像这样:

def f(n):
    return '<' + str(num) + '>'

class C(object):

    v = f(9)
    w = f(42)

然后当你想再次使用 f 时,就使用它

>>> f(4)
'<4>'

我认为这个故事的寓意是“在 Python 中,你不必将所有内容强制放入一个类中” ”。

Quite simply, the solution is that f does not need to be a member of the class. I am assuming that your thought-process has gone through a Javaish language filter causing the mental block. It goes a little something like this:

def f(n):
    return '<' + str(num) + '>'

class C(object):

    v = f(9)
    w = f(42)

Then when you want to use f again, just use it

>>> f(4)
'<4>'

I think the moral of the tale is "In Python, you don't have to force everything into a class".

余厌 2024-07-16 08:00:20

扩展 Ali A 的答案,
如果您确实想在模块命名空间中避免使用 f (并且使用像 _f 这样的非导出名称,或者设置 __all__ 是不够的),那么
您可以通过在闭包中创建类来实现这一点。

def create_C():
    def f(num):
        return '<' + str(num) + '>'

    class C(object):
        v = f(9)
        def method_using_f(self, x):  return f(x*2)
    return C

C=create_C()
del create_C

这样,C 就可以在其定义和方法中访问 f,但其他任何东西都不能访问(除非相当复杂的内省)
它的方法(C.method_using_f.im_func.func_closure))

对于大多数目的来说这可能是多余的 - 通过使用“_”前缀命名约定来记录 f 是内部的应该
一般就足够了。

[编辑] 另一种选择是在您希望使用它的方法中保留对预包装函数对象的引用。例如,通过将其设置为默认参数:(

class C(object):
    def f(num):
        return '<' + str(num) + '>'

    v = f(9)
    def method_using_f(self, x, f=f):  return f(x*2)

    del f

虽然我认为封闭方法可能更好)

Extending Ali A's answer,
if you really want to avoid f in the module namespace (and using a non-exported name like _f, or setting __all__ isn't sufficient), then
you could achieve this by creating the class within a closure.

def create_C():
    def f(num):
        return '<' + str(num) + '>'

    class C(object):
        v = f(9)
        def method_using_f(self, x):  return f(x*2)
    return C

C=create_C()
del create_C

This way C has access to f within its definition and methods, but nothing else does (barring fairly involved introspection
of its methods (C.method_using_f.im_func.func_closure))

This is probably overkill for most purposes though - documenting that f is internal by using the "_" prefix nameing convention should
generally be sufficient.

[Edit] One other option is to hold a reference to the pre-wrapped function object in the methods you wish to use it in. For example, by setting it as a default argument:

class C(object):
    def f(num):
        return '<' + str(num) + '>'

    v = f(9)
    def method_using_f(self, x, f=f):  return f(x*2)

    del f

(Though I think the closure approach is probably better)

昔日梦未散 2024-07-16 08:00:20

我相信你正在尝试这样做:

class C():
...     class F():
...         def __call__(self,num):
...             return "<"+str(num)+">"
...     f=F()
...     v=f(9)
>>> C.v
'<9>'
>>> C.f(25)
'<25>'
>>> 

也许有更好或更Pythonic的解决方案......

“在类中声明一个函数,在声明期间使用它,然后在类中使用它”

抱歉。 做不到。

“无法完成”似乎与 Python 格格不入

I believe you are trying to do this:

class C():
...     class F():
...         def __call__(self,num):
...             return "<"+str(num)+">"
...     f=F()
...     v=f(9)
>>> C.v
'<9>'
>>> C.f(25)
'<25>'
>>> 

Maybe there is better or more pythonic solution...

"declare a function in a class, use it during its declaration, and also use it later from within the class"

Sorry. Can't be done.

"Can't be done" doesn't seem to get along with Python

ぇ气 2024-07-16 08:00:20

这是一种可能性:

class _C:
    # Do most of the function definitions in here
    @classmethod
    def f(cls):
        return 'boo'

class C(_C):
    # Do the subsequent decoration in here
    v = _C.f()

This is one possibility:

class _C:
    # Do most of the function definitions in here
    @classmethod
    def f(cls):
        return 'boo'

class C(_C):
    # Do the subsequent decoration in here
    v = _C.f()
静谧 2024-07-16 08:00:20

一种选择:编写更好的staticmethod

class staticfunc(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kw):
        return self.func(*args, **kw)
    def __repr__(self):
        return 'staticfunc(%r)' % self.func

One option: write a better staticmethod:

class staticfunc(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kw):
        return self.func(*args, **kw)
    def __repr__(self):
        return 'staticfunc(%r)' % self.func
红墙和绿瓦 2024-07-16 08:00:20

让我们从头开始吧。

“在类中声明一个函数,在声明期间使用它,然后在类中使用它”

抱歉。 做不到。 “在类中”与“在声明期间使用”相矛盾。

  • 在类中意味着作为声明的一部分创建。
  • 在声明期间使用意味着它存在于类之外。 通常作为元类。 然而,还有其他方法。

目前尚不清楚 Cw 和 Cv 应该是什么。 它们只是字符串吗? 如果是这样,外部函数 f 是最好的解决方案。 “不要使命名空间混乱”有点似是而非。 毕竟,您想再次使用它。

它与 C 位于同一模块中。这就是 Python 有模块的原因。 它将函数和类绑定在一起。

import myCmod

myCmod.C.w
myCmod.C.v
myCmod.f(42)

如果 w 和 v 不是简单的字符串,那么有一个非常好的解决方案,可以提供很大的灵活性。

一般来说,对于像这样的类级(“静态”)变量,我们可以使用其他类。 完全实现所需的 API 是不可能的,但已经很接近了。

>>> class F(object):
    def __init__( self, num ):
        self.value= num
        self.format= "<%d>" % ( num, )

>>> class C(object):
    w= F(42)
    v= F(9)

>>> C.w
<__main__.F object at 0x00C58C30>
>>> C.w.format
'<42>'
>>> C.v.format
'<9>'

这样做的好处是F是一个合适的、一流的东西,可以扩展。 这不是我们试图避免暴露的“隐藏”的事情。 这是生活中的事实,所以我们不妨遵循开放/封闭原则并使其开放扩展。

Let's begin from the beginning.

"declare a function in a class, use it during its declaration, and also use it later from within the class"

Sorry. Can't be done. "In a class" contradicts "used during declaration".

  • In a class means created as part of the declaration.
  • Used during declaration means it exists outside the class. Often as a meta class. However, there are other ways.

It's not clear what C.w and C.v are supposed to be. Are they just strings? If so, an external function f is the best solution. The "not clutter the namespace" is a bit specious. After all, you want to use it again.

It's in the same module as C. That's why Python has modules. It binds the function and class together.

import myCmod

myCmod.C.w
myCmod.C.v
myCmod.f(42)

If w and v aren't simple strings, there's a really good solution that gives a lot of flexibility.

Generally, for class-level ("static") variables like this, we can use other classes. It's not possible to completely achieve the desired API, but this is close.

>>> class F(object):
    def __init__( self, num ):
        self.value= num
        self.format= "<%d>" % ( num, )

>>> class C(object):
    w= F(42)
    v= F(9)

>>> C.w
<__main__.F object at 0x00C58C30>
>>> C.w.format
'<42>'
>>> C.v.format
'<9>'

The advantage of this is that F is a proper, first-class thing that can be extended. Not a "hidden" thing that we're trying to avoid exposing. It's a fact of life, so we might as well follow the Open/Closed principle and make it open to extension.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文