【问题标题】:Does function know about the class before binding函数在绑定之前是否知道该类
【发布时间】:2023-02-08 02:41:09
【问题描述】:

有没有办法在有一个类的实例之前访问一个类(其中函数被定义为一个方法)?

class MyClass:
    def method(self):
        print("Calling me")

m1 = MyClass.method

instance = MyClass()
m2 = instance.method
print(m2.__self__.__class__)  # <class 'MyClass'>

# how to access `MyClass` from `m1`?

例如,我的代码中某处有 m1 变量,我想引用 MyClass,就像我可以从绑定方法 m2.__self__.__class__ 访问它一样。

print(m1.__qualname__)  # 'MyClass.method'

我能找到的唯一选项是__qualname__,它是一个包含类名的字符串。

【问题讨论】:

  • “我能找到的唯一选项是__qualname__,它是一个包含类名的字符串。”这可能是您更好的选择之一,但是,如果稍后添加该方法,例如def foo(self): print("foo")MyClass.baz = foo 我认为这不会成为合格名称的一部分,因此它不适用于这种情况,但也许这对您正在做的事情并不重要
  • 但基本上,MyClass.method 只是返回函数对象。据我所知,函数对象不会跟踪它被引用的所有位置,因此不会有像绑定方法对象那样的直接方法
  • 另请注意,m2.__self__.__class__ 将为您提供实例的类型,这不一定是方法已定义.你可以遍历 mro 并检查精确类的名称空间,但是,如果继承发挥作用
  • 注意方法成立类,所以甚至可能找不到类。例如,如果你想在方法装饰器中访问类,那你就不走运了,因为装饰器在类创建之前执行。

标签: python methods metaprogramming python-descriptors


【解决方案1】:

您可以使用 __qualname__ 获取类实例

    my_class = eval(m1.__qualname__.split('.')[-2])
    print(my_class)

不是最通用和最安全的方法,但应该适用于这个简单的场景。

【讨论】:

  • 这不适用于my_function.&lt;locals&gt;.MyClass.method这样的情况,所以[-2]可能在这里更好
【解决方案2】:

属性__self__本身在函数绑定实例成为方法时被Python注解。 (当在函数中运行 __get__ 代码时,该代码在某处运行,但传递的实例不同于 None )。

因此,正如人们指出的那样,您可以选择通过__qualname__ 获取类名作为字符串。否则,如果事先知道您需要此功能的函数/方法,则可以创建一个装饰器,在将它们作为类属性检索时对其类进行注释(与仅在以下情况下发生的本机注释相反)然后检索作为实例属性):

class unboundmethod:
    def __init__(self, func, cls):
        self.__func__ = func
        self.class_ = cls
        self.__self__ = None
        
    def __call__(self, instance, *args, **kw):
        if not isinstance(instance, self.class_):
            # This check is actually optional fancy stuff, since we are here! :-)
            raise TypeError(f"First parameter fo {self.__func__.__name__} must be an instance of {self.class_}")
        return self.__func__(instance, *args, **kw)
        
    def __repr__(self):
        return f"Unbound method {self.__func__!r} related to {self.class_}"


class clsbind:
    def __init__(self, func):
        self.func = func
    def __get__(self, instance, owner):
        if instance is None:
            # the function is being retrieved from the class:
            return unboundmethod(self.func, owner)
        # return control to usual method creation codepath:
        return self.func.__get__(instance, owner)
    

class MyClass:
    @clsbind
    def method(self):
        print("Calling me")

在 REPL 上你可以有这个:


In [136]: m1 = MyClass.method

In [137]: m1.class_
Out[137]: __main__.MyClass

In [138]: m1(MyClass())
Calling me

【讨论】:

    猜你喜欢
    • 2012-08-17
    • 1970-01-01
    • 2021-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-12
    • 2011-04-17
    相关资源
    最近更新 更多