猿问

为什么绑定类实例方法与绑定类方法不同?

我正在阅读python 文档并偶然发现了以下几行:

还需要注意的是,作为类实例属性的用户定义函数不会转换为绑定方法;仅当函数是类的属性时才会发生这种情况。

请有人用简单的英语解释一下这是什么意思。

我将介绍一些简写符号:

让“用户定义函数”用f表示,

让“类实例”用ci表示,而类则简单地用c表示。显然(?),ci = c(),有一些滥用符号。

另外,允许用简单的集合表示法重铸成员资格语句,例如“作为类实例的属性的用户定义函数”简写为“ vf: fεa(ci) ”,其中v : ' for all ' 和 where ' a '是(一组)属性(例如,类或类实例)的简写,“ε”表示集合隶属函数。

此外,绑定函数的过程由 ci.f(*args) 或 cf(*args) => f(ci, *args) 或 f(c, *args) 速记描述(前者指的是实例方法调用,后面指的是方法调用)

使用新引入的速记符号,文档中的引用是否意味着

vf: fεa(c), cf(*args) => f(c, *args) 是一个真实的陈述

尽管

vf: fεa(ci), ci.f(*args) => f(ci, *args) 为假?


素胚勾勒不出你
浏览 399回答 5
5回答

开满天机

将用户定义的方法设置为类的属性,这是错误的方式考虑以下示例类A和函数f:class A:&nbsp; &nbsp; passdef f(self):&nbsp; &nbsp; print("I\'m in user-defined function")a = A()该函数f是单独定义的,不在类内部。假设您想添加函数f作为a对象的实例方法。f通过设置为属性来添加它a是行不通的:import typesclass A:&nbsp; &nbsp; passdef f(self):&nbsp; &nbsp; print("I\'m in user-defined function")a = A()a.f = f# <function f at 0x000002D81F0DED30>print(a.f)# TypeError: f() missing 1 required positional argument: 'self'# a.f()因为函数f没有绑定到对象a。这就是为什么在调用a.f()它时会引发有关缺少参数的错误(如果f已绑定到a,则该对象a就是缺少参数self)。这部分是文档提到的内容:还需要注意的是,作为类实例属性的用户定义函数不会转换为绑定方法。f当然,如果 function已在 class 内定义,则所有这一切都不会发生A,这就是文档中的以下部分所述:...只有当函数是类的属性时才会发生这种情况。将用户定义的方法设置为类的属性,正确的方法要将函数添加f到对象,a您应该使用:import typesclass A:&nbsp; &nbsp; passdef f(self):&nbsp; &nbsp; print("I\'m in user-defined function")a = A()a.f = types.MethodType( f, a )# <bound method f of <__main__.A object at 0x000001EDE4768E20>>print(a.f)# Works! I'm in user-defined functiona.f()它将用户定义的方法绑定f到实例a。

慕沐林林

当您以通常的方式创建一个方法时,它将是一个绑定方法:它接收实例作为第一个参数(我们通常将其分配给“self”):class A:&nbsp; &nbsp; def meth(*args):&nbsp; &nbsp; &nbsp; &nbsp; print(args)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;a = A()a.meth()&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# (<__main__.A object at 0x7f56a137fd60>,)&nbsp;&nbsp;如果您采用一个普通函数并将其添加到类属性中,它将以相同的方式工作:def f(*args):&nbsp; &nbsp; print(args)&nbsp; &nbsp;&nbsp;A.f = fa = A()a.f()# (<__main__.A object at 0x7f56a137f700>,)实例作为第一个参数传递,它是一个绑定方法。另一方面,如果您将函数作为类实例的属性,则它将不是绑定方法=调用时不会将实例作为第一个参数传递:a = A()a.f = fa.f()# ()&nbsp;&nbsp;

哔哔one

我不认为花哨的形式逻辑符号在这里有帮助。然而,要回答这个问题:“作为类实例的属性的用户定义函数不会转换为绑定方法;只有当函数是类的属性时才会发生这种情况”是什么意思?绑定方法是依赖于类的实例作为第一个参数的方法。它将实例作为第一个参数传递,用于访问变量和函数。在 Python 3 和更高版本的 python 中,类中的所有函数默认都是绑定方法。因此,如果您创建用户定义函数作为类实例的属性,它不会自动转换为绑定方法。“类实例”只是 Python 中表达“对象”或“对象实例”在其他语言中含义的一种方式。例如:class HelloClass:&nbsp; &nbsp; greeting = 'Hello'&nbsp; &nbsp; def greet(self, name):&nbsp; &nbsp; &nbsp; &nbsp; print(f'{greeting} {name}')hc = HelloClass()hc.greet('John')这HelloClass是类,而hc是类实例。greet是一个绑定方法,至少需要一个参数(按照约定调用),该参数在调用时自动分配给类实例 - 即打印之前self的值是类实例。selfhello Johnhc现在,如果你尝试这样做:def greet_with_hi(self, name):&nbsp; &nbsp; print(f'Hi {name}')class HiClass:&nbsp; &nbsp; greet = greet_with_hihc = HiClass()hc.greet('John')这可行(尽管你的 IDE 可能会反对),但这根本不起作用:def greet_with_hi(self, name):&nbsp; &nbsp; print(f'Hi {name}')class HiClass:&nbsp; &nbsp; def __init__(self):&nbsp; &nbsp; &nbsp; &nbsp; self.greet = greet_with_hihc = HiClass()hc.greet('John')它导致TypeError: greet_with_hi() missing 1 required positional argument: 'name'. 它应该,因为.greet在 的实例上HiClass不是绑定方法,并且self greet_with_hi期望不会自动填充。

米脂

我认为最好通过例子来阐明其含义。假设我们有一个包含各种属性的类实例,这些属性是用户定义的函数。add1通过将其定义为类定义的一部分来添加。add2在实例化之前通过对类进行猴子修补来添加。add3通过在实例化后对类进行猴子修补来添加add4通过在实例化后对实例进行猴子修补来添加class Number:&nbsp; &nbsp; def __init__(self, x):&nbsp; &nbsp; &nbsp; &nbsp; self.x = x&nbsp; &nbsp; def add1(self):&nbsp; &nbsp; &nbsp; &nbsp; return self.x + 1def add2(self):&nbsp; &nbsp; return self.x + 2def add3(self):&nbsp; &nbsp; return self.x + 3def add4(self):&nbsp; &nbsp; return self.x + 4setattr(Number, 'add2', add2)two = Number(2)setattr(Number, 'add3', add3)setattr(two, 'add4', add4)print(two.add1())&nbsp; # prints 3print(two.add2())&nbsp; # prints 4print(two.add3())&nbsp; # prints 5print(two.add4())&nbsp; # TypeError: add4() missing 1 required positional argument: 'self'我们尝试调用这些。前三个都有效(在add3实例化时它不是类的属性甚至没有关系)。请注意,当我们调用这些函数时,我们不会显式传递与函数内第一个位置参数相对应的任何内容(即self)——它会自动为我们添加。这就是绑定方法的含义。它是用一个位置参数声明的,而我们明确不传递任何位置参数。但在这种情况下,add4它会抱怨缺少位置参数 - 这是因为该实例不会自动添加为第一个参数。(如果你明确使用它就会起作用two.add4(two)。)

Helenr

绑定方法 python 绑定方法是依赖于类的实例作为第一个参数的方法。它将实例作为第一个参数传递,用于访问变量和函数。在 Python 3 和更高版本的 python 中,类中的所有函数默认都是绑定方法。让我们通过一个例子来理解这个概念:# Python code to demonstrate&nbsp;# use of bound methods&nbsp;&nbsp;&nbsp;class A:&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; def func(self, arg):&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; self.arg = arg&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; print("Value of arg = ", arg)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Creating an instance&nbsp;obj = A()&nbsp; &nbsp;&nbsp;&nbsp;# bound method&nbsp;print(obj.func)&nbsp;Output:< bound method A.func of <__main__.A object at 0x7fb81c5a09e8>>这里,obj.func(arg) 由 python 翻译为 A.func(obj, arg)。实例 obj 自动作为第一个参数传递给被调用的函数,因此函数的第一个参数将用于访问对象的变量/函数。让我们看一下 Bound 方法的另一个示例。# Python code to demonstrate&nbsp;# use of bound methods&nbsp;&nbsp;&nbsp;class Car:&nbsp;&nbsp; &nbsp; # Car class created&nbsp;&nbsp; &nbsp; gears = 5&nbsp;&nbsp;&nbsp; &nbsp; # a class method to change the number of gears&nbsp;&nbsp;&nbsp; &nbsp; @classmethod&nbsp; &nbsp; def change_gears(cls, gears):&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; cls.gears = gears&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# instance of class Car created&nbsp;Car1 = Car()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("Car1 gears before calling change_gears() = ", Car1.gears)&nbsp;Car1.change_gears(6)&nbsp;&nbsp;print("Gears after calling change_gears() = ", Car1.gears)&nbsp;&nbsp;&nbsp;# bound method&nbsp;print(Car1.change_gears)&nbsp;Output:Car1 gears before calling change_gears() =&nbsp; 5Gears after calling change_gears() =&nbsp; 6<bound method Car.change_gears of <class '__main__.Car'>>上面的代码是类方法的示例。类方法类似于绑定方法,只不过实例的类作为参数而不是实例本身传递。在上面的示例中,当我们调用 Car1.change_gears(6) 时,类“Car”作为第一个参数传递。对这些绑定方法的需求 类内的方法至少需要一个参数。为了使它们成为零参数方法,必须使用“装饰器”。类的不同实例具有与其关联的不同值。例如,如果有一个类“Fruits”,那么像苹果、橙子、芒果这样的实例都是可能的。每个实例可能有不同的大小、颜色、味道和营养成分。因此,要更改特定实例的任何值,该方法必须将“self”作为参数,以允许它仅更改其属性。例子:class sample(object):&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; # Static variable for object number&nbsp;&nbsp; &nbsp; objectNo = 0&nbsp;&nbsp;&nbsp; &nbsp; def __init__(self, name1):&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; # variable to hold name&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; self.name = name1&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; # Increment static variable for each object&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; sample.objectNo = sample.objectNo + 1&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; # each object's unique number that can be&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; # considered as ID&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; self.objNumber = sample.objectNo&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; def myFunc(self):&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; print("My name is ", self.name,&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "from object ", self.objNumber)&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; def alterIt(self, newName):&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; self.name = newName&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; def myFunc2():&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; print("I am not a bound method !!!")&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# creating first instance of class sample&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;samp1 = sample("A")&nbsp;samp1.myFunc()&nbsp;&nbsp;&nbsp;# unhide the line below to see the error&nbsp;# samp1.myFunc2() #----------> error line&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# creating second instance of class sample&nbsp; &nbsp; &nbsp;samp2 = sample("B")&nbsp;samp2.myFunc()&nbsp;samp2.alterIt("C")&nbsp;samp2.myFunc()&nbsp;samp1.myFunc()&nbsp;Output:My name is&nbsp; A from object&nbsp; 1My name is&nbsp; B from object&nbsp; 2My name is&nbsp; C from object&nbsp; 2My name is&nbsp; A from object&nbsp; 1在上面的示例中,创建了两个实例,即 samp1 和 samp2。请注意,当函数 alterIt() 应用于第二个实例时,仅更改该特定实例的值。samp1.myFunc() 行将扩展为sample.myFunc(samp1)。对于此方法,不需要传递显式参数。实例 samp1 将作为参数传递给 myFunc()。samp1.myFunc2() 行将生成错误:Traceback (most recent call last):&nbsp; File "/home/4f130d34a1a72402e0d26bab554c2cf6.py", line 26, in&nbsp;&nbsp; &nbsp; samp1.myFunc2() #----------> error lineTypeError: myFunc2() takes 0 positional arguments but 1 was given这意味着该方法是未绑定的。它不接受任何实例作为参数。这些函数是未绑定函数。
随时随地看视频慕课网APP

相关分类

Python
我要回答