通过getattr访问方法 [英] Accessing methods via getattr

查看:73
本文介绍了通过getattr访问方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我偶然发现了这种行为,这表明您可以使用 getattr 来调用类实例上的方法,以替代直观命名为 operator.methodcaller 的方法:

I stumbled across this behaviour, which suggests that you can use getattr to call methods on a class instance, as an alternative to the intuitively named operator.methodcaller:

from operator import methodcaller

class Foo():
    def __init__(self, lst):
        self.lst = lst

    def summer(self):
        return sum(self.lst)

my_obj = Foo(range(11))

res1 = methodcaller('summer')(my_obj)  # 55
res2 = getattr(my_obj, 'summer')()     # 55

assert res1 == res2

我想从内部了解为什么.是否因为所有方法也是属性?出现这种情况是因为 dir(Foo) dir(my_obj)包含'summer'.但是我从未听说过被称为类或类实例的 attributes 的方法,例如 Python中的方法"没有提及?

I'd like to understand, internally, why this works. Is it because all methods are also attributes? This seems to be the case because dir(Foo) or dir(my_obj) includes 'summer'. But I have never heard methods referred to as attributes of a class or class instance, e.g. this isn't mentioned in What is a "method" in Python?

文档中有解释,其中提到我无法理解的数据属性"和非数据属性"之间的区别.

There is an explanation in the docs which mentions differentiation between "data attributes" and "non-data attributes" which I failed to understand.

更新:@Amadan的评论澄清了上面的大部分内容.我唯一不了解的是文档摘录:

Update: Comments by @Amadan have clarified most of the above. The only remaining bit I do not understand is this excerpt from the docs:

如果您仍然不了解方法的工作原理,请查看实施也许可以澄清问题.当非数据属性引用实例的实例,然后搜索实例的类.如果名称表示作为函数对象的有效类属性,方法对象是通过打包(指向)实例对象来创建的和刚在抽象对象中找到的功能对象:这是方法对象.

If you still don’t understand how methods work, a look at the implementation can perhaps clarify matters. When a non-data attribute of an instance is referenced, the instance’s class is searched. If the name denotes a valid class attribute that is a function object, a method object is created by packing (pointers to) the instance object and the function object just found together in an abstract object: this is the method object.

那么非数据属性是通过检查它是否可调用来确定的,还是有其他方法可以用来确定它是一个函数对象?指向实例对象的打包指针"是什么意思?什么是抽象对象?

So is a non-data attribute determined by checking whether it is callable, or is there some other way that's used to determine it's a function object? What does "packing pointers" to the instance object mean? What's an abstract object?

推荐答案

是的,方法只是包含适当形式的函数的属性(它们必须接受至少一个参数,即接收者,通常称为 self ).

Yes, methods are just attributes containing functions of appropriate form (they must accept at least one parameter, the receiver, usually called self).

下面是一个解释引用段落的示例:

Here's an example that explains the quoted paragraph:

class Foo():
    def a(self):
        print("FOO")

foo = Foo()
foo.a()
# => FOO

因此, def 实际上在 Foo 上附加了 a 属性作为未绑定方法"(如我们在检查它时所看到的那样)-的意思是,它不知道谁正在接收它)(在Python 2中),或者只是一个普通的函数值(在Python 3中):

So, def there actually attached an attribute a to Foo as an "unbound method" (as you can see when we inspect it - meaning, it doesn't know who is receiving it yet) in Python 2, or just a plain function value (in Python 3):

Foo.a
# => <unbound method Foo.a>          (Python 2)
# => <function Foo.a at 0x10919fea0> (Python 3)

您可以像调用任何函数一样调用它(...一个例外,在Python 2中:第一个参数必须为类型为 Foo ):

You can invoke it just like any function (... with one exception, in Python 2: the first argument must be of type Foo):

Foo.a(foo)
# => FOO

Foo.a(42)
# => TypeError: unbound method a() must be called with Foo instance as first argument (got int instance instead) (Python 2)
# => 42 (Python 3)

但是,如果尝试在实例(实例属性引用")上找到它,则该实例现在作为绑定方法"报告:

However, if you try to find it on an instance ("instance attribute reference"), it is now reporting as a "bound method":

foo.a
# => <bound method Foo.a of <__main__.Foo instance at 0x10ba11320>>

这可以说是将实例对象和功能对象打包(指向它们的指针)":引用了实例对象< __ main__.Foo instance at 0x10ba11320> (又名 foo )和对函数对象 Foo.a 的引用,在一个包中,我们将其称为绑定方法".

This can be said to be "packing (pointers to) the instance object and the function object together": there is a reference to the instance object, <__main__.Foo instance at 0x10ba11320> (a.k.a. foo), and a reference to the function object, Foo.a, in one package we call "bound method".

与JavaScript不同,它不是纯粹的语法问题.在JavaScript中,方法调用和函数调用之间的区别在于调用本身:如果有点,则是方法调用:

Unlike JavaScript, it's not purely a syntactic thing. In JavaScript, the difference between a method invocation and a function invocation is in the call itself: if it has a dot, it's a method invocation:

// JavaScript
let foo = new Foo()
foo.a();                // method invocation: `a` is told that the receiver is `foo`
let z = foo.a; z()      // function invocation, `a` doesn't know about `foo`

在Python中,绑定函数将其接收方携带在其中:

In Python, the bound function carries its receiver inside it:

// Back to Python
foo.a()                 // method invocation: `a` is told that the receiver is `foo`
z = foo.a; z()          // STILL method invocation; `z` knows both `foo` and `Foo.a`

此呼叫甚至如何工作?本段的其余部分说明:

How does this calling even work? The rest of the paragraph explains:

使用实参列表调用方法对象时,将根据实例对象和实参列表构造一个新的实参列表,并使用此新的实参列表来调用功能对象.

When the method object is called with an argument list, a new argument list is constructed from the instance object and the argument list, and the function object is called with this new argument list.

所以,当我们说

foo.a()

它将把 foo.a 解压缩为 Foo.a foo ;在接收者的前面加上 foo 到参数列表中(我在这里没有,所以参数列表是 [foo] + [] 作为最后一个参数列表的 [foo] ),最后被称为的是 Foo.a(foo).顺便说一句,这就是您可以手动执行的操作:

it will unpack foo.a into Foo.a and foo; prepend foo, the receiver, to the list of the arguments (I have none here, so the argument list is [foo] + [] for the final argument list of [foo]), and what ends up being called is Foo.a(foo). Incidentally, that's exactly what you can do manually:

Foo.a(foo)
# => FOO

即使具有内置对象:

"-".join(["foo", "bar", "baz"])
# => 'foo-bar-baz'
str.join("-", ["foo", "bar", "baz"])
# => 'foo-bar-baz'

在这里,-".join 是一个绑定方法,它将接收方-" 和函数 str.join 打包在一起;当我们调用第一行时,接收方-" 放在其他参数 [[" foo," bar," baz]] 的前面 [-",["foo","bar","baz"]] 的最终参数列表,并将其发送到位于 join str 的属性(即 str.join ).这使我们在第一行和第二行之间有了清晰的翻译.

Here, "-".join is a bound method that packs together the receiver "-" and the function str.join; when we invoke the first line, the receiver "-" is prepended to the rest of the arguments [["foo", "bar", "baz"]] for the final argument list of ["-", ["foo", "bar", "baz"]], and that's sent to the function that is sitting in the join attribute of str (i.e. str.join). This gives us a clear translation between the first line and the second line.

这篇关于通过getattr访问方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆