我正在阅读python docs,偶然发现以下几行:
同样重要的是要注意,作为类实例属性的用户定义函数不会转换为绑定方法。仅当函数是类的属性时,这种情况才会发生。
请,有人用简单的英语解释这是什么意思。
我将介绍一些速记符号:
让“ 用户定义的函数”由 f ,
let' class instance '用 ci 表示,而 class 用 c 简单表示。显然(?),ci = c(),但有些滥用符号。
还允许以简单的集合符号重铸成员资格声明,例如,“ 用户定义的函数,它们是类实例的属性”的缩写为“ vf:fεa(ci) / em>”,其中 v :“ forall ”,其中“ a ”是(一组)属性(例如类或类实例),“ε”表示集合成员函数。
此外,绑定函数的过程由ci.f(* args)或cf(* args)=> f(ci,* args)或f(c,* args)简化表示(前者指调用 instance 方法调用,而稍后引用 class 方法调用)
使用新引入的速记符号,文档中的引号是否暗示
vf:fεa(c),c.f(* args)=> f(c,* args)是一个真实的语句
同时
vf:fεa(ci),ci.f(* args)=> f(ci,* args)是假的?
答案 0 :(得分: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
中定义了函数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
。
答案 1 :(得分:3)
我认为花哨的形式逻辑符号在这里没有帮助。
但是,要回答这个问题:“作为类实例属性的用户定义函数不会转换为绑定方法;仅当函数是类的属性时才会发生这种情况”是什么意思?
一个绑定方法是一个依赖于类实例作为第一个参数的方法。它将实例作为第一个参数传递,该参数用于访问变量和函数。在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
),该参数在被调用时会自动分配给类实例-即在打印{{1之前,self
的值}}是hello John
类实例。
现在,如果您尝试这样做:
hc
这行得通(尽管您的IDE可能会反对),但这根本行不通:
def greet_with_hi(self, name):
print(f'Hi {name}')
class HiClass:
greet = greet_with_hi
hc = HiClass()
hc.greet('John')
它导致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
期望不会自动填充。
答案 2 :(得分:3)
以通常的方式创建方法时,它将是一个绑定方法:它将实例作为第一个参数(我们通常将其分配给“ self”):
class A:
def meth(*args):
print(args)
a = A()
a.meth()
# (<__main__.A object at 0x7f56a137fd60>,)
如果您采用普通函数并将其添加到 class 属性中,则它将以相同的方式工作:
def f(*args):
print(args)
A.f = f
a = A()
a.f()
# (<__main__.A object at 0x7f56a137f700>,)
实例作为第一个参数传递,这是一个绑定方法。
另一方面,如果您将该函数设为该类的 instance 的属性,则该方法将不是绑定方法=不会将实例作为第一个参数传递调用时:
a = A()
a.f = f
a.f()
# ()
答案 3 :(得分:2)
我认为通过示例可以最好地阐明其含义。
假设我们有一个包含各种属性的类实例,这些属性是用户定义的函数。
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)
,则可以使用。)
答案 4 :(得分:1)
绑定方法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>>
在这里
python将obj.func(arg)转换为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”类作为第一个参数传递。
需要这些绑定方法 类中的方法将至少使用一个参数。为了使它们成为零参数方法,必须使用“装饰器”。一个类的不同实例具有与之关联的不同值。
例如,如果有一个“水果”类,则可能有苹果,橙子,芒果等实例。每个实例中的大小,颜色,味道和营养成分都可能不同。因此,要更改特定实例的任何值,该方法必须将“ 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
这意味着该方法是未绑定的。它不接受任何实例作为参数。这些函数是未绑定的函数。
来源: Geeks For Geeks: Bound Methods Python
Geeks For Geeks: Bound, unbound and static methods in Python
答案 5 :(得分:1)