我有一段我想理解的代码,即使有了现有的答案,我也真的无法理解以下代码的目的,有人可以帮我理解吗?
我已经在这里查看了各种相关问题(__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} }设置为什么?
答案 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}}的引用。由于在我们的例子中,self
是self
的实例,因此此调用返回对绑定到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.bar
或f.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
实例。