5 回答
TA贡献1786条经验 获得超12个赞
将用户定义的方法设置为类的属性,这是错误的方式
考虑以下示例类A和函数f:
class A:
pass
def f(self):
print("I\'m in user-defined function")
a = A()
该函数f是单独定义的,不在类内部。
假设您想添加函数f作为a对象的实例方法。
f通过设置为属性来添加它a是行不通的:
import types
class A:
pass
def f(self):
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 types
class A:
pass
def f(self):
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 function
a.f()
它将用户定义的方法绑定f到实例a。
TA贡献2016条经验 获得超9个赞
当您以通常的方式创建一个方法时,它将是一个绑定方法:它接收实例作为第一个参数(我们通常将其分配给“self”):
class A:
def meth(*args):
print(args)
a = A()
a.meth()
# (<__main__.A object at 0x7f56a137fd60>,)
如果您采用一个普通函数并将其添加到类属性中,它将以相同的方式工作:
def f(*args):
print(args)
A.f = f
a = A()
a.f()
# (<__main__.A object at 0x7f56a137f700>,)
实例作为第一个参数传递,它是一个绑定方法。
另一方面,如果您将函数作为类实例的属性,则它将不是绑定方法=调用时不会将实例作为第一个参数传递:
a = A()
a.f = f
a.f()
# ()
TA贡献1854条经验 获得超8个赞
我不认为花哨的形式逻辑符号在这里有帮助。
然而,要回答这个问题:“作为类实例的属性的用户定义函数不会转换为绑定方法;只有当函数是类的属性时才会发生这种情况”是什么意思?
绑定方法是依赖于类的实例作为第一个参数的方法。它将实例作为第一个参数传递,用于访问变量和函数。在 Python 3 和更高版本的 python 中,类中的所有函数默认都是绑定方法。
因此,如果您创建用户定义函数作为类实例的属性,它不会自动转换为绑定方法。“类实例”只是 Python 中表达“对象”或“对象实例”在其他语言中含义的一种方式。
例如:
class HelloClass:
greeting = 'Hello'
def greet(self, name):
print(f'{greeting} {name}')
hc = HelloClass()
hc.greet('John')
这HelloClass是类,而hc是类实例。greet是一个绑定方法,至少需要一个参数(按照约定调用),该参数在调用时自动分配给类实例 - 即打印之前self的值是类实例。selfhello Johnhc
现在,如果你尝试这样做:
def greet_with_hi(self, name):
print(f'Hi {name}')
class HiClass:
greet = greet_with_hi
hc = HiClass()
hc.greet('John')
这可行(尽管你的 IDE 可能会反对),但这根本不起作用:
def greet_with_hi(self, name):
print(f'Hi {name}')
class HiClass:
def __init__(self):
self.greet = greet_with_hi
hc = HiClass()
hc.greet('John')
它导致TypeError: greet_with_hi() missing 1 required positional argument: 'name'. 它应该,因为.greet在 的实例上HiClass不是绑定方法,并且self greet_with_hi期望不会自动填充。
TA贡献1836条经验 获得超3个赞
我认为最好通过例子来阐明其含义。
假设我们有一个包含各种属性的类实例,这些属性是用户定义的函数。
add1
通过将其定义为类定义的一部分来添加。add2
在实例化之前通过对类进行猴子修补来添加。add3
通过在实例化后对类进行猴子修补来添加add4
通过在实例化后对实例进行猴子修补来添加
class Number:
def __init__(self, x):
self.x = x
def add1(self):
return self.x + 1
def add2(self):
return self.x + 2
def add3(self):
return self.x + 3
def add4(self):
return self.x + 4
setattr(Number, 'add2', add2)
two = Number(2)
setattr(Number, 'add3', add3)
setattr(two, 'add4', add4)
print(two.add1()) # prints 3
print(two.add2()) # prints 4
print(two.add3()) # prints 5
print(two.add4()) # TypeError: add4() missing 1 required positional argument: 'self'
我们尝试调用这些。
前三个都有效(在add3实例化时它不是类的属性甚至没有关系)。
请注意,当我们调用这些函数时,我们不会显式传递与函数内第一个位置参数相对应的任何内容(即self)——它会自动为我们添加。这就是绑定方法的含义。它是用一个位置参数声明的,而我们明确不传递任何位置参数。
但在这种情况下,add4它会抱怨缺少位置参数 - 这是因为该实例不会自动添加为第一个参数。(如果你明确使用它就会起作用two.add4(two)。)
TA贡献1780条经验 获得超3个赞
绑定方法 python 绑定方法是依赖于类的实例作为第一个参数的方法。它将实例作为第一个参数传递,用于访问变量和函数。在 Python 3 和更高版本的 python 中,类中的所有函数默认都是绑定方法。
让我们通过一个例子来理解这个概念:
# Python code to demonstrate
# use of bound methods
class A:
def func(self, arg):
self.arg = arg
print("Value of arg = ", arg)
# Creating an instance
obj = A()
# bound method
print(obj.func)
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
# use of bound methods
class Car:
# Car class created
gears = 5
# a class method to change the number of gears
@classmethod
def change_gears(cls, gears):
cls.gears = gears
# instance of class Car created
Car1 = Car()
print("Car1 gears before calling change_gears() = ", Car1.gears)
Car1.change_gears(6)
print("Gears after calling change_gears() = ", Car1.gears)
# bound method
print(Car1.change_gears)
Output:
Car1 gears before calling change_gears() = 5
Gears after calling change_gears() = 6
<bound method Car.change_gears of <class '__main__.Car'>>
上面的代码是类方法的示例。类方法类似于绑定方法,只不过实例的类作为参数而不是实例本身传递。在上面的示例中,当我们调用 Car1.change_gears(6) 时,类“Car”作为第一个参数传递。
对这些绑定方法的需求 类内的方法至少需要一个参数。为了使它们成为零参数方法,必须使用“装饰器”。类的不同实例具有与其关联的不同值。
例如,如果有一个类“Fruits”,那么像苹果、橙子、芒果这样的实例都是可能的。每个实例可能有不同的大小、颜色、味道和营养成分。因此,要更改特定实例的任何值,该方法必须将“self”作为参数,以允许它仅更改其属性。
例子:
class sample(object):
# Static variable for object number
objectNo = 0
def __init__(self, name1):
# variable to hold name
self.name = name1
# Increment static variable for each object
sample.objectNo = sample.objectNo + 1
# each object's unique number that can be
# considered as ID
self.objNumber = sample.objectNo
def myFunc(self):
print("My name is ", self.name,
"from object ", self.objNumber)
def alterIt(self, newName):
self.name = newName
def myFunc2():
print("I am not a bound method !!!")
# creating first instance of class sample
samp1 = sample("A")
samp1.myFunc()
# unhide the line below to see the error
# samp1.myFunc2() #----------> error line
# creating second instance of class sample
samp2 = sample("B")
samp2.myFunc()
samp2.alterIt("C")
samp2.myFunc()
samp1.myFunc()
Output:
My name is A from object 1
My name is B from object 2
My name is C from object 2
My name is A from object 1
在上面的示例中,创建了两个实例,即 samp1 和 samp2。请注意,当函数 alterIt() 应用于第二个实例时,仅更改该特定实例的值。samp1.myFunc() 行将扩展为sample.myFunc(samp1)。对于此方法,不需要传递显式参数。实例 samp1 将作为参数传递给 myFunc()。samp1.myFunc2() 行将生成错误:
Traceback (most recent call last):
File "/home/4f130d34a1a72402e0d26bab554c2cf6.py", line 26, in
samp1.myFunc2() #----------> error line
TypeError: myFunc2() takes 0 positional arguments but 1 was given
这意味着该方法是未绑定的。它不接受任何实例作为参数。这些函数是未绑定函数。
添加回答
举报