提问人:richzilla 提问时间:4/26/2010 最后编辑:Karl Knechtelrichzilla 更新时间:5/11/2023 访问量:1032074
“self”参数的目的是什么?为什么需要它?
What is the purpose of the `self` parameter? Why is it needed?
问:
请看这个例子:
class MyClass:
def func(self, name):
self.name = name
我知道这是指 的特定实例。但是,为什么必须明确地包含为参数呢?为什么我们需要在方法的代码中使用?其他一些语言将其隐含,或者使用特殊语法来代替。self
MyClass
func
self
self
有关设计决策的与语言无关的注意事项,请参阅将 this/self pointer 强制显式的优点是什么?。
要关闭 OP 省略方法的 self
参数并得到 TypeError
的调试问题,请使用 TypeError:method() 接受 1 个位置参数,但给出了 2 个。如果 OP 在方法主体中省略了 self.
并得到 NameError
,请考虑如何调用类中的函数?。
答:
它是对类实例对象的显式引用。
评论
您需要使用的原因是 Python 不使用特殊语法来引用实例属性。Python 决定以一种使方法所属的实例自动传递而不是自动接收的方式执行方法:methods 的第一个参数是调用该方法的实例。这使得方法与函数完全相同,并留下实际名称由您使用(尽管这是惯例,当您使用其他东西时,人们通常会皱眉头。 对代码来说并不特别,它只是另一个对象。self.
self
self
Python本可以做一些其他的事情来区分普通名称和属性 - 像Ruby那样的特殊语法,或者像C++和Java那样需要声明,或者可能更不同的东西 - 但它没有。Python 的宗旨是让事情变得明确,让什么是什么变得清晰,虽然它并不完全在所有地方都这样做,但它确实为实例属性做到了这一点。这就是为什么分配给实例属性需要知道要分配给哪个实例的原因,这就是为什么它需要 .self.
评论
cls
cls
self
self
cls
bob
fnord
this
self
self
self
this
self
是对对象本身的对象引用,因此,它们是相同的。
Python 方法不会在对象本身的上下文中调用。 在 Python 中可用于处理自定义对象模型或其他东西。self
以下摘录自关于 self 的 Python 文档:
与 Modula-3 一样,[在 Python 中]没有从其方法中引用对象成员的简写:方法函数是用一个表示对象的显式第一个参数声明的,该参数由调用隐式提供。
通常,方法的第一个参数称为 self。这只不过是一个约定:self这个名字对Python来说绝对没有特殊的含义。但是请注意,如果不遵循约定,您的代码对其他 Python 程序员来说可能不太易读,并且也可以想象编写依赖于此类约定的类浏览器程序。
有关详细信息,请参阅有关类的 Python 文档教程。
除了已经说明的所有其他原因外,它还允许更轻松地访问被覆盖的方法;您可以调用 .Class.some_method(inst)
它有用的地方的一个例子:
class C1(object):
def __init__(self):
print "C1 init"
class C2(C1):
def __init__(self): #overrides C1.__init__
print "C2 init"
C1.__init__(self) #but we still want C1 to init the class too
>>> C2()
"C2 init"
"C1 init"
我喜欢这个例子:
class A:
foo = []
a, b = A(), A()
a.foo.append(5)
b.foo # [5]
class A:
def __init__(self):
self.foo = []
a, b = A(), A()
a.foo.append(5)
b.foo # []
评论
self
a.foo
A.foo
foo
a
b
A()
a.foo
A().foo
a
A()
b
foo
我们来看一个简单的向量类:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
我们想要一种计算长度的方法。如果我们想在类中定义它,它会是什么样子?
def length(self):
return math.sqrt(self.x ** 2 + self.y ** 2)
当我们将其定义为全局方法/函数时,它应该是什么样子?
def length_global(vector):
return math.sqrt(vector.x ** 2 + vector.y ** 2)
所以整个结构保持不变。我怎样才能利用它?如果我们暂时假设我们没有为我们的类编写方法,我们可以这样做:length
Vector
Vector.length_new = length_global
v = Vector(3, 4)
print(v.length_new()) # 5.0
这之所以有效,是因为 的第一个参数 可以重新用作 中的参数。如果没有明确的 .length_global
self
length_new
self
理解显式需求的另一种方法是查看 Python 在哪些方面添加了一些语法糖。当你记住,基本上,一个像self
v_instance.length()
在内部转换为
Vector.length(v_instance)
很容易看出适合哪里。您实际上并没有在 Python 中编写实例方法;你写的是类方法,它必须将实例作为第一个参数。因此,您必须将实例参数显式放置在某个位置。self
评论
Vector.length_new = length_global
我将使用不使用类的代码进行演示:
def state_init(state):
state['field'] = 'init'
def state_add(state, x):
state['field'] += x
def state_mult(state, x):
state['field'] *= x
def state_getField(state):
return state['field']
myself = {}
state_init(myself)
state_add(myself, 'added')
state_mult(myself, 2)
print( state_getField(myself) )
#--> 'initaddedinitadded'
类只是避免一直传递这种“状态”事物的一种方式(以及其他一些好东西,如初始化、类组合、很少需要的元类,以及支持自定义方法来覆盖运算符)。
现在让我们使用内置的 python 类机制来演示上面的代码,以展示它基本上是一回事。
class State(object):
def __init__(self):
self.field = 'init'
def add(self, x):
self.field += x
def mult(self, x):
self.field *= x
s = State()
s.add('added') # self is implicitly passed in
s.mult(2) # self is implicitly passed in
print( s.field )
[从重复的封闭式问题中迁移了我的答案]
评论
它的用法类似于 Java 中关键字的使用,即给出对当前对象的引用。this
评论
它遵循 Python 禅宗“显式比隐式好”。它确实是对类对象的引用。例如,在 Java 和 PHP 中,它被称为 .this
如果是模型上的字段,则可通过 访问它。user_type_name
self.user_type_name
假设您有一个类,其中包含定义为以下内容的方法:ClassA
methodA
class ClassA:
def methodA(self, arg1, arg2):
... # do something
并且是此类的实例。objectA
现在,当被调用时,python 会在内部为您将其转换为:objectA.methodA(arg1, arg2)
ClassA.methodA(objectA, arg1, arg2)
变量引用对象本身。self
评论
self
__init__
MyClass()
MyClass.__call__
type
MyClass.__new__
self
MyClass.__init__
MyClass.__new__
object.__new__
__class__
__dict__
在方法中,self 是指新创建的对象;在其他类方法中,它引用其方法被调用的实例。__init__
自我,作为一个名字,只是一个约定俗成,随心所欲地称呼它!但是在使用它时,例如要删除对象,您必须使用相同的名称: ,其中在__del__(var)
var
__init__(var,[...])
你也应该看看,以获得更大的图景。这篇文章可能会有所帮助。cls
请看下面的例子,它清楚地解释了self
class Restaurant(object):
bankrupt = False
def open_branch(self):
if not self.bankrupt:
print("branch opened")
#create instance1
>>> x = Restaurant()
>>> x.bankrupt
False
#create instance2
>>> y = Restaurant()
>>> y.bankrupt = True
>>> y.bankrupt
True
>>> x.bankrupt
False
self
用于/需要区分实例。
资料来源: python 中的 self 变量解释 - Pythontips
评论
Python不是为面向对象编程而构建的语言,与Java或C++不同。
首先,方法属于整个类(静态方法)或类的对象(实例)(对象方法)。
在 Python 中调用静态方法时,只需编写一个包含常规参数的方法。
class Animal():
def staticMethod():
print "This is a static method"
但是,一个对象(即实例)方法,它需要你创建一个对象(即实例,在本例中为动物),需要参数。self
class Animal():
def objectMethod(self):
print "This is an object method which needs an instance of a class"
该方法还用于引用类中的变量字段。self
class Animal():
#animalName made in constructor
def Animal(self):
self.animalName = "";
def getAnimalName(self):
return self.animalName
在本例中,指的是整个类的 animalName 变量。切记:如果在方法中创建了新变量(称为局部变量),则将不起作用。该变量仅在该方法运行时存在。要定义字段(整个类的变量),必须在类方法之外定义它们。self
self
如果你不明白我在说什么,那么谷歌“面向对象编程”。一旦你理解了这一点,你甚至不需要:)问这个问题。
评论
staticMethod()
objectMethod(self)
Animal.staticMethod()
objectMethod()
a = Animal(); a.objectMethod()
def getAnimalName
不破坏您尝试返回的字符串,并引用类的实例,而不是其中的任何字段。self
实例化对象时,对象本身将传递到参数中。self
因此,对象的数据绑定到该对象。下面是一个示例,说明人们可能希望如何可视化每个对象的数据可能看起来是什么样子。请注意如何替换为对象的名称。我并不是说下面的这个示例图是完全准确的,但它希望能帮助人们直观地看到 .self
self
将 Object 传递到参数中,以便对象可以保留自己的数据。self
尽管这可能并不完全准确,但请考虑实例化(创建和分配内部值)对象的过程,如下所示:创建对象时,该对象使用该类作为其(对象)自己的数据和方法的模板。如果不将对象自己的变量名称传递到参数中,类中的属性和方法将保留为常规模板,并且不会引用(属于)对象。因此,通过将对象的名称传递到参数中,这意味着如果从一个类实例化 100 个对象,则 100 个对象中的每一个都可以跟踪其(每个对象)自己的数据和方法。self
self
摘要:类是通用的(非超特定的)模板,新创建的对象可以将其自己的特定数据传递到其中(不一定会影响可以从同一类创建的其余对象),从而减少复制粘贴的代码,用于创建许多具有相同模式的对象。 用于指定应使用特定对象的数据而不是其他一些数据。self
如下图所示:
评论
这是因为按照 python 的设计方式,替代方案几乎行不通。Python 旨在允许在隐式(a-la Java/C++)或显式(a-la ruby)都不起作用的上下文中定义方法或函数。让我们举一个使用 python 约定的显式方法的例子:this
@
def fubar(x):
self.x = x
class C:
frob = fubar
现在该函数将不起作用,因为它会假设这是一个全局变量(并且也是如此)。另一种方法是使用替换的全局范围(其中是对象)执行方法。fubar
self
frob
self
隐式方法是
def fubar(x)
myX = x
class C:
frob = fubar
这意味着它将被解释为 in(和 in)中的局部变量。这里的替代方法是使用替换的局部作用域来执行方法,该作用域在调用之间保留,但这将消除方法局部变量的可能性。myX
fubar
frob
但是,目前的情况很好:
def fubar(self, x)
self.x = x
class C:
frob = fubar
这里作为方法调用时,将通过参数接收调用它的对象,并且仍然可以使用对象作为参数调用并工作相同(我认为它和我认为相同)。frob
self
fubar
C.frob
我很惊讶没有人提起 Lua。Lua 也使用了 'self' 变量,但可以省略,但仍然使用。C++ 对“this”做同样的事情。我看不出有任何理由必须在每个函数中声明“self”,但您仍然应该能够像使用 lua 和 C++ 一样使用它。对于一种以简短而自豪的语言来说,它要求你声明 self 变量是很奇怪的。
首先,self 是一个传统名称,你可以用其他任何东西(连贯)来代替它。
它指的是对象本身,因此当您使用它时,您声明 .name 和 .age 是您将要创建的 Student 对象(请注意,而不是 Student 类)的属性。
class Student:
#called each time you create a new Student instance
def __init__(self,name,age): #special method to initialize
self.name=name
self.age=age
def __str__(self): #special method called for example when you use print
return "Student %s is %s years old" %(self.name,self.age)
def call(self, msg): #silly example for custom method
return ("Hey, %s! "+msg) %self.name
#initializing two instances of the student class
bob=Student("Bob",20)
alice=Student("Alice",19)
#using them
print bob.name
print bob.age
print alice #this one only works if you define the __str__ method
print alice.call("Come here!") #notice you don't put a value for self
#you can modify attributes, like when alice ages
alice.age=20
print alice
这个论点的使用,通常被称为,并不难理解,为什么有必要?或者为什么明确提到它?我想,对于大多数查找此问题的用户来说,这是一个更大的问题,或者如果不是,他们在继续学习 python 时肯定会遇到同样的问题。我建议他们阅读这几篇博客:self
请注意,它不是关键字。
每个类方法(包括 init)的第一个参数始终是对类的当前实例的引用。按照惯例,这个参数总是被命名为 self。在 init 方法中,self 指的是新创建的对象;在其他类方法中,它引用其方法被调用的实例。例如,下面的代码与上面的代码相同。
2:为什么我们有这种方式,为什么我们不能像Java那样将其作为参数消除,而使用关键字来代替
我想补充的另一件事是,一个可选参数允许我在类中声明静态方法,而不是编写 .self
self
代码示例:
class MyClass():
def staticMethod():
print "This is a static method"
def objectMethod(self):
print "This is an object method which needs an instance of a class, and that is what self refers to"
PS:这仅适用于 Python 3.x。
在以前的版本中,您必须显式添加装饰器,否则参数是强制性的。@staticmethod
self
自我
是不可避免的。
只有一个问题应该是隐含的或明确的。吉多·范·罗苏姆(Guido van Rossum
)解决了这个问题,他说自我
必须留下来。self
那么自我
住在哪里呢?
如果我们只坚持函数式编程,我们就不需要了。
一旦我们进入 Python OOP,我们就会在那里找到。self
self
以下是该方法的典型用例class C
m1
class C:
def m1(self, arg):
print(self, ' inside')
pass
ci =C()
print(ci, ' outside')
ci.m1(None)
print(hex(id(ci))) # hex memory address
该程序将输出:
<__main__.C object at 0x000002B9D79C6CC0> outside
<__main__.C object at 0x000002B9D79C6CC0> inside
0x2b9d79c6cc0
所以保存类实例的内存地址。其目的是保存示例方法的引用,并让我们明确访问该引用。self
self
请注意,有三种不同类型的类方法:
- 静态方法(读取:函数),
- 类方法,
- 实例方法(已提及)。
self 的行为类似于当前对象名称或类的实例。
# Self explanation.
class classname(object):
def __init__(self,name):
self.name=name
# Self is acting as a replacement of object name.
#self.name=object1.name
def display(self):
print("Name of the person is :",self.name)
print("object name:",object1.name)
object1=classname("Bucky")
object2=classname("ford")
object1.display()
object2.display()
###### Output
Name of the person is : Bucky
object name: Bucky
Name of the person is : ford
object name: Bucky
从文档中,
方法的特殊之处在于实例对象作为函数的第一个参数传递。在我们的示例中,调用完全等同于 。通常,调用具有 n 个参数列表的方法等效于使用参数列表调用相应的函数,该参数列表是通过在第一个参数之前插入方法的实例对象而创建的。
x.f()
MyClass.f(x)
在此之前,相关片段,
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
x = MyClass()
我想说,至少对于 Python 来说,self 参数可以被认为是一个占位符。 看看这个:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p1 = Person("John", 36)
print(p1.name)
print(p1.age)
在这种情况下,Self 和许多其他人被用作存储名称值的方法。但是,在那之后,我们使用 p1 将其分配给我们正在使用的类。然后,当我们打印它时,我们使用相同的 p1 关键字。
希望这对 Python 有所帮助!
“self”关键字包含类的引用,是否要使用它取决于您,但如果您注意到,每当您在 Python 中创建新方法时,Python 都会自动为您编写 self 关键字。如果你做一些研发,你会注意到,如果你在一个类中创建两个方法,并试图在另一个方法中调用一个,除非你添加 self(类的引用),否则它不会识别方法。
class testA:
def __init__(self):
print('ads')
def m1(self):
print('method 1')
self.m2()
def m2(self):
print('method 2')
下面的代码会引发无法解析的引用错误。
class testA:
def __init__(self):
print('ads')
def m1(self):
print('method 1')
m2() #throws unresolvable reference error as class does not know if m2 exist in class scope
def m2(self):
print('method 2')
现在让我们看看下面的例子
class testA:
def __init__(self):
print('ads')
def m1(self):
print('method 1')
def m2():
print('method 2')
现在,当您创建类 testA 的对象时,您可以使用类对象调用方法 m1(),因为方法 m1() 包含 self 关键字
obj = testA()
obj.m1()
但是如果你想调用方法 m2(),因为 is 没有自引用,所以你可以直接使用类名调用 m2(),如下所示
testA.m2()
但是在实践中使用 self 关键字,因为它还有其他好处,例如在内部创建全局变量等。
我的小 2 美分
在这个 Person 类中,我们用 self 定义了 init 方法,有趣的是这里需要注意的是 self 和实例变量 p 的内存位置是相同的<__main__.Person object at 0x106a78fd0>
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def say_hi(self):
print("the self is at:", self)
print((f"hey there, my name is {self.name} and I am {self.age} years old"))
def say_bye(self):
print("the self is at:", self)
print(f"good to see you {self.name}")
p = Person("john", 78)
print("the p is at",p)
p.say_hi()
p.say_bye()
因此,如上所述,self 和实例变量是同一个对象。
“self”一词是指类的实例
class foo:
def __init__(self, num1, num2):
self.n1 = num1 #now in this it will make the perimeter num1 and num2 access across the whole class
self.n2 = num2
def add(self):
return self.n1 + self.n2 # if we had not written self then if would throw an error that n1 and n2 is not defined and we have to include self in the function's perimeter to access it's variables
评论
@name
self.name