在 Python 类声明中调用方法的最佳方式?
假设我正在声明一个类 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
很简单,解决方案是 f 不需要是该类的成员。 我假设您的思维过程已经通过了 Javaish 语言过滤器,导致了心理障碍。 它有点像这样:
然后当你想再次使用 f 时,就使用它
我认为这个故事的寓意是“在 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:
Then when you want to use f again, just use it
I think the moral of the tale is "In Python, you don't have to force everything into a class".
扩展 Ali A 的答案,
如果您确实想在模块命名空间中避免使用 f (并且使用像 _f 这样的非导出名称,或者设置 __all__ 是不够的),那么
您可以通过在闭包中创建类来实现这一点。
这样,C 就可以在其定义和方法中访问 f,但其他任何东西都不能访问(除非相当复杂的内省)
它的方法(
C.method_using_f.im_func.func_closure
))对于大多数目的来说这可能是多余的 - 通过使用“_”前缀命名约定来记录 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.
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:
(Though I think the closure approach is probably better)
我相信你正在尝试这样做:
也许有更好或更Pythonic的解决方案......
“无法完成”似乎与 Python 格格不入
I believe you are trying to do this:
Maybe there is better or more pythonic solution...
"Can't be done" doesn't seem to get along with Python
这是一种可能性:
This is one possibility:
一种选择:编写更好的
staticmethod
:One option: write a better
staticmethod
:让我们从头开始吧。
“在类中声明一个函数,在声明期间使用它,然后在类中使用它”
抱歉。 做不到。 “在类中”与“在声明期间使用”相矛盾。
目前尚不清楚 Cw 和 Cv 应该是什么。 它们只是字符串吗? 如果是这样,外部函数
f
是最好的解决方案。 “不要使命名空间混乱”有点似是而非。 毕竟,您想再次使用它。它与 C 位于同一模块中。这就是 Python 有模块的原因。 它将函数和类绑定在一起。
如果 w 和 v 不是简单的字符串,那么有一个非常好的解决方案,可以提供很大的灵活性。
一般来说,对于像这样的类级(“静态”)变量,我们可以使用其他类。 完全实现所需的 API 是不可能的,但已经很接近了。
这样做的好处是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".
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.
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.
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.