自我的目的是什么?

时间:2010-04-25 20:22:29

标签: python class oop self

Python中self字的目的是什么?我理解它指的是从该类创建的特定对象,但我不明白为什么它明确需要作为参数添加到每个函数。为了说明,在Ruby中我可以这样做:

class myClass
    def myFunc(name)
        @name = name
    end
end

我很容易理解。但是在Python中我需要包含self

class myClass:
    def myFunc(self, name):
        self.name = name

有人可以通过这个跟我说话吗?这不是我在(无可否认有限的)经历中遇到的事情。

24 个答案:

答案 0 :(得分:646)

您需要使用self.的原因是因为Python不使用@语法来引用实例属性。 Python决定以某种方式执行方法,使方法所属的实例自动传递,但不自动接收:方法的第一个参数是方法的实例被召唤。这使得方法与函数完全相同,并保留实际名称以供您使用(尽管self是惯例,当您使用其他内容时,人们通常会对您不满。)self是对代码来说并不特殊,它只是另一个对象。

Python本可以做其他事情来区分普通名称和属性 - 像Ruby这样的特殊语法,或者需要像C ++和Java这样的声明,或者可能是更不同的东西 - 但事实并非如此。 Python的所有内容都是为了使事情变得明确,让它显而易见的是什么,虽然它并不是完全在任何地方完成,但它确实是为了实例属性。这就是为什么分配一个实例属性需要知道要分配的实例,这就是它需要self.的原因。

答案 1 :(得分:400)

我们来看一个简单的矢量类:

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,这是不可能的。


理解显式self需求的另一种方法是看Python在哪里添加一些语法糖。当你记住,基本上,这是一个像

这样的电话
v_instance.length()

内部转换为

Vector.length(v_instance)

很容易看出self适合的位置。你实际上并没有在Python中编写实例方法;你写的是类方法,它必须将实例作为第一个参数。因此,您必须明确地将实例参数放在某处。

答案 2 :(得分:340)

我们假设您有一个班级ClassA,其中包含的方法methodA定义为:

def methodA(self, arg1, arg2):
    # do something

ObjectA是此类的一个实例。

现在调用ObjectA.methodA(arg1, arg2)时,python会在内部将其转换为:

ClassA.methodA(ObjectA, arg1, arg2)

self变量引用对象本身。

答案 3 :(得分:189)

实例化对象时,对象本身会传递给self参数。

enter image description here

因此,对象的数据绑定到对象。下面是一个示例,说明如何可视化每个对象的数据外观。注意如何用对象名称替换“self”。我并不是说下面这个示例图表是完全准确的,但它有望用于可视化自我的使用。

enter image description here

将Object传递给self参数,以便对象可以保留自己的数据。

虽然这可能不完全准确,但请考虑实例化这样的对象的过程:当创建对象时,它使用该类作为其自己的数据和方法的模板。如果不将其自己的名称传递给self参数,则类中的属性和方法将保留为通用模板,并且不会引用(属于)对象。因此,通过将对象的名称传递给self参数,意味着如果从一个类中实例化了100个对象,则它们都可以跟踪自己的数据和方法。

见下图:

enter image description here

答案 4 :(得分:71)

我喜欢这个例子:

class A: 
    foo = []
a, b = A(), A()
a.foo.append(5)
b.foo
ans: [5]

class A: 
    def __init__(self): 
        self.foo = []
a, b = A(), A()
a.foo.append(5)
b.foo
ans: []

答案 5 :(得分:34)

我将使用代码演示不使用类

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 )

[从重复的封闭式问题中迁移了我的答案]

答案 6 :(得分:17)

以下摘录来自Python documentation about self

  

与Modula-3一样,[在Python中]没有用于从其方法引用对象成员的简短方法:方法函数使用表示对象的显式第一个参数声明,该参数由调用隐式提供。

     

通常,方法的第一个参数称为self。这只不过是一个惯例:名称self对Python来说绝对没有特殊意义。但请注意,如果不遵循惯例,您的代码可能对其他Python程序员来说可读性较低,并且可以想象可能会编写依赖于此类约定的类浏览器程序。

有关详细信息,请参阅Python documentation tutorial on classes

答案 7 :(得分:17)

除了已经陈述的所有其他原因之外,它还允许更轻松地访问被覆盖的方法;你可以致电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"

答案 8 :(得分:12)

它的用法类似于在Java中使用this关键字,即提供对当前对象的引用。

答案 9 :(得分:11)

与Java或C ++不同,Python不是为面向对象编程而构建的语言。

在Python中调用静态方法时,只需在其中编写一个带有常规参数的方法。

class Animal():
    def staticMethod():
        print "This is a static method"

但是,在这种情况下,一个对象方法需要你创建一个变量(动物),需要自我参数

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

在这种情况下,self指的是整个类的animalName变量。记住:如果方法中有变量,则self不起作用。该变量仅在该方法运行时存在。对于定义字段(整个类的变量),您必须在类方法外定义它们。

如果您不理解我所说的单词,那么谷歌"面向对象编程。"一旦你理解了这一点,你甚至不需要问这个问题:)。

答案 10 :(得分:7)

它遵循Python zen“显式优于隐式”。它确实是对您的类对象的引用。例如,在Java和PHP中,它被称为this

如果user_type_name是您模型上的字段,则可以self.user_type_name访问它。

答案 11 :(得分:5)

self是对象本身的对象引用,因此它们是相同的。 Python方法不在对象本身的上下文中调用。 Python中的self可用于处理自定义对象模型或其他内容。

答案 12 :(得分:5)

首先,自我是一个传统的名字,你可以把任何其他东西(连贯的)代替。

它指的是对象本身,因此当您使用它时,您声明.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

Code is here

答案 13 :(得分:4)

我很惊讶没有人带来Lua。 Lua也使用'self'变量,但它可以省略但仍然使用。 C ++对'this'做同样的事情。我没有看到任何理由必须在每个函数中声明'self',但你仍然可以像使用lua和C ++一样使用它。对于一种以简短而自豪的语言而言,奇怪的是它需要你声明自变量。

答案 14 :(得分:3)

请看下面的示例,该示例清楚地解释了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用于区分实例。

答案 15 :(得分:3)

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

答案 16 :(得分:3)

使用通常称为self的参数并不难理解,因为为什么有必要?还是至于为什么要明确提及呢?我想,对于大多数查询此问题的用户来说,这是一个更大的问题,或者如果不是,则在继续学习python时,他们肯定会有相同的问题。我建议他们阅读以下两个博客:

1: Use of self explained

请注意,它不是关键字。

  

每个类方法(包括init)的第一个参数始终是对类当前实例的引用。按照惯例,此参数始终命名为self。在init方法中,self指的是新创建的对象;在其他类方法中,它引用其方法被调用的实例。例如,下面的代码与上面的代码相同。

2: Why do we have it this way and why can we not eliminate it as an argument, like Java, and have a keyword instead

我想添加的另一件事是,可选的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参数。

答案 17 :(得分:1)

__init__方法中,self引用新创建的对象;在其他类方法中,它指的是调用其方法的实例。

self,作为名称, 只是一个约定 ,根据需要调用它!但是在使用它时,例如要删除对象,你必须使用相同的名称:__del__(var)var中使用__init__(var,[...])

你也应该看看cls,让 更大的图片 。这post可能会有所帮助。

答案 18 :(得分:0)

self是不可避免的。

只有questionself的隐式或显式。 Guido van Rossum回答了self has to stay这个问题。

那么self住哪里?

如果我们只坚持函数式编程,就不需要self。 进入 Python OOP 后,我们在此处找到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的目的是为实例方法保留引用,并使我们能够显式访问该引用。


注意,有三种不同类型的类方法:

  • 静态方法(阅读:函数),
  • 类方法
  • instance方法(已提及)。

答案 19 :(得分:0)

来自docs

关于方法的特殊之处在于,实例对象作为函数的第一个参数传递。在我们的示例中,呼叫x.f()MyClass.f(x)完全等效。通常,调用带有n个参数列表的方法等效于调用带有参数列表的函数,该参数列表是通过在第一个参数之前插入方法的实例对象而创建的。

相关代码段之前,

class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'

x = MyClass()

答案 20 :(得分:0)

我至少要说对于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有帮助!

答案 21 :(得分:0)

“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

答案 22 :(得分:-1)

“ 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(),则由于该方法没有自引用,因此您可以使用如下所示的类名直接调用m2()

testA.m2()

但是请实践中使用self关键字,因为它还有其他好处,例如在内部创建全局变量等等。

答案 23 :(得分:-3)

它是类实例对象的显式引用。