Python 为 class 定义的包装函数的 `self` 参数
Python's `self` argument for class defined wrapped func
我有一个简化的代码:
class A:
def foo(*args, **kwargs):
def foo_sub(*args, **kwargs):
print(f"foo args: {args}")
return foo_sub
def bar(*args, **kwargs):
print(f"bar args: {args}")
a = A()
class B:
foo = a.foo(1)
bar = a.bar
a.foo(2)()
a.bar()
B.foo()
B.bar()
B().foo()
B().bar()
并且有输出:
foo args: ()
bar args: (<__main__.A object at 0x7f9763e38080>,)
foo args: ()
bar args: (<__main__.A object at 0x7f9763e38080>,)
foo args: (<__main__.B object at 0x7f9763e38828>,)
bar args: (<__main__.A object at 0x7f9763e38080>,)
我需要将 foo
func 包装在 A
class 中,我真的不明白为什么 B().foo()
将 self
作为参数传递?我该如何预防?
我不知道你想在这里用所有这些包装器和东西做什么。您可能需要查看装饰器或上下文管理器来干净地执行此操作。
- https://docs.python.org/3/glossary.html#term-decorator
- https://docs.python.org/3/reference/compound_stmts.html#grammar-token-decorator
- https://docs.python.org/3/library/functools.html#functools.wraps
- https://docs.python.org/3/library/stdtypes.html#context-manager-types
回答你的问题,一种方法是定义静态方法,@MisterMiyagi 也已经指出了这一点。通常在编程中,静态方法是 class 的方法,您可以在不需要 class instance/object 的情况下调用它们。这意味着此类方法没有引用 class 实例的 s/object 状态(以 class attributes/fields 的形式)。在 Python 中,普通 class 方法可以通过这个自动 self
参数访问 instance/object 本身。如果您不想要它,请将其定义为 @staticmethod
。
A static method does not receive an implicit first argument.
If you access a method (a function defined in a class namespace)
through an instance, you get a special object: a bound method (also
called instance method) object. When called, it will add the self
argument to the argument list.
- “通过一个实例”就像你用
B()
做的那样 B().foo()
。
- https://docs.python.org/3/library/stdtypes.html#methods
解决您的问题的快速代码(请注意,正如我之前指出的,有更好的替代方法):
class A:
@staticmethod # Or use the inline-decorator stlye as @kaya3 mentioned
def foo(*args, **kwargs):
def foo_sub(*args, **kwargs):
print(f"foo args: {args}")
return foo_sub
@staticmethod
def bar(*args, **kwargs):
print(f"bar args: {args}")
a = A()
class B:
@staticmethod
def foo(*args, **kwargs):
return a.foo(1)(*args, **kwargs)
@staticmethod
def bar(*args, **kwargs):
return a.bar(*args, **kwargs)
a.foo(2)()
a.bar()
B.foo()
B.bar()
B().foo()
B().bar()
输出:
foo args: ()
bar args: ()
foo args: ()
bar args: ()
foo args: ()
bar args: ()
否则,如果您真的非常想完全跳过 self
属性并一路破解,您可以触发 obj.method.__func__(*args, **kwargs)
,如 https://docs.python.org/3/library/stdtypes.html#methods
中所述
- 警告:这个建议是骇人听闻的。谨慎行事:)
感谢@kaya3 staticmethod
以及所有回复的人!
我找到了元类的解决方案
class BMeta(type):
def __new__(cls, name, bases, dct):
if isinstance(dct.get("foo"), FunctionType):
dct["foo"] = staticmethod(dct["foo"])
return super().__new__(cls, name, bases, dct)
class B(metaclass=BMeta):
foo = a.foo(1)
bar = a.bar
我有一个简化的代码:
class A:
def foo(*args, **kwargs):
def foo_sub(*args, **kwargs):
print(f"foo args: {args}")
return foo_sub
def bar(*args, **kwargs):
print(f"bar args: {args}")
a = A()
class B:
foo = a.foo(1)
bar = a.bar
a.foo(2)()
a.bar()
B.foo()
B.bar()
B().foo()
B().bar()
并且有输出:
foo args: ()
bar args: (<__main__.A object at 0x7f9763e38080>,)
foo args: ()
bar args: (<__main__.A object at 0x7f9763e38080>,)
foo args: (<__main__.B object at 0x7f9763e38828>,)
bar args: (<__main__.A object at 0x7f9763e38080>,)
我需要将 foo
func 包装在 A
class 中,我真的不明白为什么 B().foo()
将 self
作为参数传递?我该如何预防?
我不知道你想在这里用所有这些包装器和东西做什么。您可能需要查看装饰器或上下文管理器来干净地执行此操作。
- https://docs.python.org/3/glossary.html#term-decorator
- https://docs.python.org/3/reference/compound_stmts.html#grammar-token-decorator
- https://docs.python.org/3/library/functools.html#functools.wraps
- https://docs.python.org/3/library/stdtypes.html#context-manager-types
回答你的问题,一种方法是定义静态方法,@MisterMiyagi 也已经指出了这一点。通常在编程中,静态方法是 class 的方法,您可以在不需要 class instance/object 的情况下调用它们。这意味着此类方法没有引用 class 实例的 s/object 状态(以 class attributes/fields 的形式)。在 Python 中,普通 class 方法可以通过这个自动 self
参数访问 instance/object 本身。如果您不想要它,请将其定义为 @staticmethod
。
A static method does not receive an implicit first argument.
If you access a method (a function defined in a class namespace) through an instance, you get a special object: a bound method (also called instance method) object. When called, it will add the self argument to the argument list.
- “通过一个实例”就像你用
B()
做的那样B().foo()
。 - https://docs.python.org/3/library/stdtypes.html#methods
解决您的问题的快速代码(请注意,正如我之前指出的,有更好的替代方法):
class A:
@staticmethod # Or use the inline-decorator stlye as @kaya3 mentioned
def foo(*args, **kwargs):
def foo_sub(*args, **kwargs):
print(f"foo args: {args}")
return foo_sub
@staticmethod
def bar(*args, **kwargs):
print(f"bar args: {args}")
a = A()
class B:
@staticmethod
def foo(*args, **kwargs):
return a.foo(1)(*args, **kwargs)
@staticmethod
def bar(*args, **kwargs):
return a.bar(*args, **kwargs)
a.foo(2)()
a.bar()
B.foo()
B.bar()
B().foo()
B().bar()
输出:
foo args: ()
bar args: ()
foo args: ()
bar args: ()
foo args: ()
bar args: ()
否则,如果您真的非常想完全跳过 self
属性并一路破解,您可以触发 obj.method.__func__(*args, **kwargs)
,如 https://docs.python.org/3/library/stdtypes.html#methods
- 警告:这个建议是骇人听闻的。谨慎行事:)
感谢@kaya3 staticmethod
以及所有回复的人!
我找到了元类的解决方案
class BMeta(type):
def __new__(cls, name, bases, dct):
if isinstance(dct.get("foo"), FunctionType):
dct["foo"] = staticmethod(dct["foo"])
return super().__new__(cls, name, bases, dct)
class B(metaclass=BMeta):
foo = a.foo(1)
bar = a.bar