__get __()Python中的方法/函数

时间:2019-05-18 20:05:04

标签: python

我有一段我想理解的代码,即使有了现有的答案,我也真的无法理解以下代码的目的,有人可以帮我理解吗?

我已经在这里查看了各种相关问题(__get__()),但找不到具体答案。我知道下面的类正在尝试动态创建方法(可能我们从无法找到属性的__getattr__()方法进入该类)并将该方法返回给调用者。我已经在需要理解的代码行上方发表了评论。

class MethodGen(object):

    def __getattr__(self, name):
        method = self.method_gen(name)
        if method:
           return self.method_gen(name)


    def method_gen(self, name):

        def method(*args, **kwargs):
            print("Creating a method here")

        # Below are the two lines of code I need help understanding with
        method.__name__ = name
        setattr(self, name, method.__get__(self))

        return method

如果我没记错的话,已经设置了method()函数的属性__name__,但是在setattr()函数中,则设置了类MethodGen,{{1} }设置为什么?

3 个答案:

答案 0 :(得分:1)

这个问题确实让我很感兴趣。提供的两个答案似乎并不能说明全部问题。困扰我的是这一行:

setattr(self, name, method.__get__(self))

代码未进行设置,因此在某个时刻将调用method.__get__ 。相反,method.__get__实际上是被呼叫!但是,难道不是实际上引用了对象的特定属性(在这种情况下为MethodGen的实例)时调用此__get__方法的想法吗?如果您阅读这些文档,则会给人留下的印象……属性链接到实现__get__的描述符,并且该实现确定引用该属性时返回的内容。但是再次,这不是这里发生的事情。这一切在那之前发生。那么,这到底是怎么回事?

答案是HERE。关键语言是这样:

  

为支持方法调用,函数包括__get__()方法,用于   属性访问期间的绑定方法。这意味着所有功能   是非数据描述符,当它们是   从对象调用。

method.__get__(self)正是此处所描述的。因此,method.__get__(self)实际正在执行的操作是返回对绑定到"method" function的{​​{1}}的引用。由于在我们的例子中,selfself的实例,因此此调用返回对绑定到MethodGen实例的"method" function的引用。在这种情况下,MethodGen方法与引用属性的行为无关。而是,此调用将函数引用转换为方法引用!

因此,现在我们可以快速引用创建的方法。但是,当绑定了具有正确名称的属性时,如何设置它以便在正确的时间调用它呢?这就是__get__部分的所在。此调用采用我们的新方法,并将其绑定到实例上名称为setattr(self, name, X)的属性。

以上所有这些都是原因:

name

正在向setattr(self, name, method.__get__(self)) 类的实例self添加一个新方法。

MethodGen部分并不那么重要。仅执行上面讨论的代码行,即可提供您真正想要的所有行为。这个额外的步骤只是在我们的新方法上附加了一个名称,以便要求该方法名称的代码(例如使用自省代码编写文档的代码)将获得正确的名称。真正重要的是实例属性的名称...传递给method_gen的名称...并为该方法“命名”。

答案 1 :(得分:0)

有趣的是,以前从未见过的有趣的事情似乎很难维护(可能会使一些其他开发人员想吊死你)。

我更改了一些代码,以便您可以看到更多发生的事情。

class MethodGen(object):

    def method_gen(self, name):
        print("Creating a method here")
        def method(*args, **kwargs):
            print("Calling method")
            print(args) # so we can see what is actually being outputted

        # Below are the two lines of code I need help understanding with
        method.__name__ = name # These the method name equal to name (i.e. we can call the method this way) 
        # The following is adding the new method to the current class.
        setattr(self, name, method.__get__(self)) # Adds the method to this class

        # I would do: setattr(self, name, method) though and remove the __get__

        return method # Returns the emthod

m = MethodGen()
test = m.method_gen("my_method") # I created a method in MethodGen class called my_method
test("test") # It returned a pointer to the method that I can use
m.my_method("test") # Or I can now call that method in the class.
m.method_gen("method_2")
m.method_2("test2")

答案 2 :(得分:0)

请考虑以下课程:

class Foo:
    def bar(self):
        print("hi")

f = Foo()
f.bar()

bar是具有功能的 class 属性。由于function实现了描述符协议,因此,以Foo.barf.bar的形式访问它不会 not 立即返回函数本身。它会导致调用函数的__get__方法,并且那个返回原始函数(如Foo.bar)或类型为 new 的值instancemethod(与f.bar中一样)。 f.bar()被评估为Foo.bar.__get__(f, Foo)()

method_gen使用名为method的函数,并将通过调用函数的__get__方法检索到的 actual 方法附加到对象。目的是使这样的事情起作用:

>>> m = MethodGen()
>>> n = MethodGen()
>>> m.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MethodGen' object has no attribute 'foo'
>>> n.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MethodGen' object has no attribute 'foo'
>>> m.method_gen('foo')
<function foo at 0x10465c758>
>>> m.foo()
Creating a method here
>>> n.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MethodGen' object has no attribute 'foo'

最初,MethodGen除了method_gen之外没有其他方法。您可以看到在两个实例中的任何一个实例上调用名为foo的方法时引发的异常。但是,调用method_gen会为该特定实例 just 附加一个新方法。调用m.method_gen("foo")之后,m.foo()调用method_gen定义的方法。该调用不会影响MethodGen之类的其他n实例。