首页 文章

自我的目的是什么?

提问于
浏览
925

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

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

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

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

谁能跟我说说这个?这不是我在(无可否认的有限)经历中遇到的事情 .

19 回答

  • 1

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

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

  • -3

    实例化对象时,对象本身将传递给self参数 .

    enter image description here

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

    enter image description here

    Object被传递给self参数,以便对象可以保持自己的数据 .

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

    见下图:

    enter image description here

  • 388

    通常称为 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 参数 .

  • 609

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

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

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

    但是,在这种情况下,需要您创建变量的对象方法(在本例中为Animal)需要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
    

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

    如果你不理解我所说的单词,那么Google就是“面向对象的编程” . 一旦你理解了这一点,你甚至不需要问这个问题:) .

  • 66

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

    Python可以做其他事情来区分普通名称和属性 - 像Ruby这样的特殊语法,或者需要像C和Java那样的声明,或者可能是更不同的东西 - 但是它并没有使事情变得明确,显而易见的是's what, and although it doesn't在任何地方完全做到了,它确实做了例如属性 . 那个's why assigning to an instance attribute needs to know what instance to assign to, and that'为什么它需要 self. .

  • 17

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

  • 306

    是因为按照python的设计方式,替代方案几乎不起作用 . Python旨在允许在一个上下文中定义方法或函数,其中隐式 this (a-la Java / C)或显式 @ (a-la ruby)都不具有使用python约定的显式方法的示例:

    def fubar(x):
        self.x = x
    
    class C:
        frob = fubar
    

    现在 fubar 函数不起作用,因为它假设 self 是一个全局变量(也在 frob 中) . 另一种方法是使用替换的全局范围执行方法(其中 self 是对象) .

    隐含的方法是

    def fubar(x)
        myX = x
    
    class C:
        frob = fubar
    

    这意味着 myX 将被解释为 fubar 中的局部变量(以及 frob 中) . 这里的替代方法是执行具有替换的局部范围的方法,该范围在调用之间保留,但这将删除方法局部变量的可能性 .

    然而目前的情况很好:

    def fubar(self, x)
         self.x = x
    
     class C:
         frob = fubar
    

    这里当作为方法调用时 frob 将通过 self 参数接收它所调用的对象,并且仍然可以使用对象作为参数调用 fubar 并且工作相同(我认为它与_243207相同) .

  • 163

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

    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)
    

    所以整个结构保持不变 . 我怎么能利用这个呢?如果我们暂时假设我们没有为 Vector 类编写 length 方法,我们可以这样做:

    Vector.length_new = length_global
    v = Vector(3, 4)
    print(v.length_new()) # 5.0
    

    这是有效的,因为 length_global 的第一个参数可以重新用作 length_new 中的 self 参数 . 如果没有明确的 self ,这是不可能的 .


    理解显式 self 的需要的另一种方法是查看Python添加一些语法糖的位置 . 当你记住,基本上,一个电话就像

    v_instance.length()
    

    内部转变为

    Vector.length(v_instance)
    

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

  • 3

    我喜欢这个例子:

    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: []
    
  • 4

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

  • 4

    以下摘录来自Python documentation about self

    与Modula-3一样,[在Python中]没有用于从其方法引用对象成员的简短方法:方法函数使用表示对象的显式第一个参数声明,该参数由调用隐式提供 . 通常,方法的第一个参数称为self . 这只不过是一个惯例:名称self对Python来说绝对没有特殊意义 . 但请注意,如果不遵循惯例,您的代码可能对其他Python程序员来说可读性较低,并且可以想象可能会编写依赖于此类约定的类浏览器程序 .

    有关更多信息,请参阅Python documentation tutorial on classes .

  • 3

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

  • 12

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

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

  • 11

    假设您有一个类 ClassA ,其中包含一个方法 methodA ,定义如下:

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

    ObjectA 是此类的一个实例 .

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

    ClassA.methodA(ObjectA, arg1, arg2)
    

    self 变量引用对象本身 .

  • 3

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

  • 4

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

    我将用代码演示 does not use classes

    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 )
    

    [从重复的封闭问题中移出我的答案]

  • 33

    看一下下面的例子,它清楚地解释了 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 来区分实例 .

  • 16

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

    自我,作为一个名字, just a convention ,按你的意愿调用它!但是当使用它时,例如删除对象,你必须使用相同的名称: __del__(var) ,其中 var__init__(var,[...]) 中使用

    您也应该看看 cls ,以获得 the bigger picture . 这个post可能会有所帮助 .

相关问题