【问题标题】:What do __init__ and self do in Python?__init__ 和 self 在 Python 中做了什么?
【发布时间】:2010-10-12 02:58:51
【问题描述】:

我正在学习 Python 编程语言,但遇到了一些我不完全理解的东西。

在这样的方法中:

def method(self, blah):
    def __init__(?):
        ....
    ....

self 是做什么的?它是什么意思?是强制性的吗?

__init__ 方法有什么作用?为什么有必要? (等等)

我认为它们可能是 OOP 构造,但我不太了解。

【问题讨论】:

    标签: python oop self


    【解决方案1】:

    是的,你是对的,这些是 oop 结构。

    __init__ 是类的构造函数。 self 参数指的是对象的实例(如 C++ 中的 this)。

    class Point:
        def __init__(self, x, y):
            self._x = x
            self._y = y
    

    在为对象分配内存后调用__init__ 方法:

    x = Point(1,2)
    

    如果您想将值与对象一起保存,请务必在对象的方法中使用self 参数。例如,如果您像这样实现__init__ 方法:

    class Point:
        def __init__(self, x, y):
            _x = x
            _y = y
    

    您的xy 参数将存储在堆栈上的变量中,并在init 方法超出范围时被丢弃。将这些变量设置为 self._xself._y 会将这些变量设置为 Point 对象的成员(在对象的生命周期内可访问)。

    注意在此答案中对“构造函数”一词的使用进行了一些澄清。从技术上讲,“构造函数”的职责在 Python 中分为两种方法。这些方法是__new__(负责分配内存)和__init__(这里讨论过,负责初始化新创建的实例)。

    【讨论】:

    • 那么有什么理由不希望self 出现在构造函数中?为什么还要指定,如果是隐式的不是更好吗?
    • 据我所知,__init __ 不是构造函数,它是创建任何对象时都会执行的第一个方法,__init __ 用于设置对象。 __ new __ 是python中的构造函数。
    • 对于那些阅读此答案的人来说,这是完全错误的。 __init__ 不分配内存空间。预计会初始化实例属性。在内存中分配的是__new__
    • @black 答案的文本实际上是“为对象分配内存时调用 init 方法”。它没有说 init 分配内存,它说它是在分配内存时调用的。也许值得通过将“何时”更改为“之后”来澄清:)
    【解决方案2】:

    一个简短的说明性示例

    希望对您有所帮助,这里有一个简单的例子,我用来理解在类中声明的变量和在__init__ 函数中声明的变量之间的区别:

    class MyClass(object):
        i = 123
        def __init__(self):
            self.i = 345
         
    a = MyClass()
    print(a.i)
    print(MyClass.i)
    

    输出:

    345
    123
    

    【讨论】:

    • 有趣的观察,但我认为你走错了路。使用 print MyClass.i 看起来更像是在调用“静态”变量 i。与 a.i 一样,您正在调用成员变量 i。在我看来,init 只是一个构造函数,在创建类的对象时首先执行。
    • 这就是我试图通过这个示例“向自己解释”的内容 - __init__ 设置的变量是传递给类的 instances 的内容,而不是具有相同名称的类本身的“静态”变量...
    • 我认为值得注意的是,您创建的第一个 i (i=123) 是一个对象变量,而第二个 i (self.i = 345) 是一个实例变量。虽然实例变量对于类的每个实例可以具有不同的值,但类变量在从该类创建的所有实例中都是相同的。 (当然也可以在代码中更改类变量)。所以“静态”变量的正确术语是对象变量和实例变量在类方法中声明(在这种情况下是 init 方法,但当然也可以是另一种方法)。
    【解决方案3】:

    自我是做什么的?它意味着是什么?是否强制

    每个类方法(包括 init)的第一个参数始终是对当前类实例的引用。按照惯例,这个参数总是命名为self。在init方法中,self指的是新创建的对象;在其他类方法中,它指的是被调用方法的实例。

    Python 不会强迫您使用self”。你可以给它任何你想要的名字。但请记住方法定义中的第一个参数是对对象的引用。 Python 为您将self 参数添加到列表中;调用方法时不需要包含它。 如果你没有在 init 方法中提供 self 那么你会得到一个错误

    TypeError: __init___() takes no arguments (1 given)
    

    init 方法有什么作用?为什么有必要? (等等)

    init 是初始化的缩写。它是一个构造函数,当你创建一个类的实例并且没有必要时会调用它。但通常我们的习惯是编写初始化方法来设置对象的默认状态。如果您最初不愿意设置对象的任何状态,则不需要编写此方法。

    【讨论】:

      【解决方案4】:

      类对象支持两种操作:属性引用和实例化

      属性引用使用用于 Python 中所有属性引用的标准语法:obj.name。有效的属性名称是创建类对象时类名称空间中的所有名称。因此,如果类定义如下所示:

      class MyClass:
          """A simple example class"""
          i = 12345
      
          def f(self):
              return 'hello world'
      

      那么MyClass.iMyClass.f 是有效的属性引用,分别返回一个整数和一个函数对象。类属性也可以赋值,所以你可以通过赋值来改变MyClass.i的值。 __doc__ 也是一个有效属性,返回属于该类的文档字符串:“A simple example class”。

      类实例化使用函数表示法。假设类对象是一个返回类的新实例的无参数函数。例如:

      x = MyClass()
      

      实例化操作(“调用”一个类对象)创建一个空对象。许多类喜欢创建具有针对特定初始状态定制的实例的对象。因此,一个类可以定义一个名为__init__() 的特殊方法,如下所示:

      def __init__(self):
          self.data = []
      

      当类定义__init__() 方法时,类实例化会自动为新创建的类实例调用__init__()。所以在这个例子中,一个新的、初始化的实例可以通过以下方式获得:

      x = MyClass()
      

      当然,__init__() 方法可能具有更大灵活性的参数。在这种情况下,给类实例化运算符的参数将传递给__init__()。例如,

      class Complex:
          def __init__(self, realpart, imagpart):
              self.r = realpart
              self.i = imagpart
      
      x = Complex(3.0, -4.5)
      x.r, x.i
      

      取自官方documentation,最后对我帮助最大。


      这是我的例子

      class Bill():
          def __init__(self,apples,figs,dates):
              self.apples = apples
              self.figs = figs
              self.dates = dates
              self.bill = apples + figs + dates
              print ("Buy",self.apples,"apples", self.figs,"figs 
                      and",self.dates,"dates. 
                      Total fruitty bill is",self.bill," pieces of fruit :)")
      

      当您创建 Bill 类的实例时:

      purchase = Bill(5,6,7)
      

      你得到:

      > Buy 5 apples 6 figs and 7 dates. Total fruitty bill is 18  pieces of
      > fruit :)
      

      【讨论】:

        【解决方案5】:

        只是一个问题的演示。

        class MyClass:
        
            def __init__(self):
                print('__init__ is the constructor for a class')
        
            def __del__(self):
                print('__del__ is the destructor for a class')
        
            def __enter__(self):
                print('__enter__ is for context manager')
                return self
        
            def __exit__(self, exc_type, exc_value, traceback):
                print('__exit__ is for context manager')
        
            def greeting(self):
                print('hello python')
        
        
        if __name__ == '__main__':
            with MyClass() as mycls:
                mycls.greeting()
        

        $ python3 class.objects_instantiation.py
        __init__ is the constructor for a class
        __enter__ is for context manager
        hello python
        __exit__ is for context manager
        __del__ is the destructor for a class
        

        【讨论】:

          【解决方案6】:

          在这段代码中:

          class Cat:
              def __init__(self, name):
                  self.name = name
              def info(self):
                  print 'I am a cat and I am called', self.name
          

          这里__init__ 充当类的构造函数,当实例化对象时,调用此函数。 self 代表实例化对象。

          c = Cat('Kitty')
          c.info()
          

          以上语句的结果如下:

          I am a cat and I am called Kitty
          

          【讨论】:

            【解决方案7】:

            Python __init__self 它们是做什么的?

            self 是做什么的?它是什么意思?是强制性的吗?

            __init__ 方法有什么作用?为什么有必要? (等等)

            给出的例子不正确,所以让我根据它创建一个正确的例子:

            class SomeObject(object):
            
                def __init__(self, blah):
                    self.blah = blah
            
                def method(self):
                    return self.blah 
            

            当我们创建对象的实例时,会调用__init__ 来在对象创建后对其进行自定义。也就是说,当我们用下面的'blah'(可以是任何东西)调用SomeObject 时,它会作为参数传递给__init__ 函数,blah

            an_object = SomeObject('blah')
            

            self 参数是将分配给an_objectSomeObject 的实例。

            稍后,我们可能想在这个对象上调用一个方法:

            an_object.method()
            

            进行点分查找,即an_object.method,将实例绑定到函数的实例,并且该方法(如上所述)现在是“绑定”方法 - 这意味着我们不需要显式传递方法调用的实例。

            方法调用获取实例,因为它被绑定在虚线查找上,并且在被调用时,然后执行它被编程执行的任何代码。

            按照约定,隐式传递的self 参数称为self。我们可以使用任何其他合法的 Python 名称,但如果您将其更改为其他名称,您可能会被其他 Python 程序员涂上焦油和羽化。

            __init__ 是一个特殊的方法,documented in the Python datamodel documentation。它在实例创建后立即调用(通常通过__new__ - 尽管__new__ 不是必需的,除非您将子类化为不可变数据类型)。

            【讨论】:

              【解决方案8】:

              简而言之:

              1. self 正如它所暗示的那样,指的是自身——调用该方法的对象。也就是说,如果您有 N 个对象调用该方法,那么 self.a 将为 N 个对象中的每一个引用一个单独的变量实例。想象一下每个对象有 N 个变量 a 的副本
              2. __init__ 在其他 OOP 语言(如 C++/Java)中称为构造函数。基本思想是它是一个特殊方法,当该类的对象被创建时会自动调用

              【讨论】:

                【解决方案9】:
                # Source: Class and Instance Variables
                # https://docs.python.org/2/tutorial/classes.html#class-and-instance-variables
                
                class MyClass(object):
                    # class variable
                    my_CLS_var = 10
                
                    # sets "init'ial" state to objects/instances, use self argument
                    def __init__(self):
                        # self usage => instance variable (per object)
                        self.my_OBJ_var = 15
                
                        # also possible, class name is used => init class variable
                        MyClass.my_CLS_var = 20
                
                
                def run_example_func():
                    # PRINTS    10    (class variable)
                    print MyClass.my_CLS_var
                
                    # executes __init__ for obj1 instance
                    # NOTE: __init__ changes class variable above
                    obj1 = MyClass()
                
                    # PRINTS    15    (instance variable)
                    print obj1.my_OBJ_var
                
                    # PRINTS    20    (class variable, changed value)
                    print MyClass.my_CLS_var
                
                
                run_example_func()
                

                【讨论】:

                  【解决方案10】:

                  试试这个代码。希望对很多像我一样的C程序员学习Py有所帮助。

                  #! /usr/bin/python2
                  
                  class Person:
                  
                      '''Doc - Inside Class '''
                  
                      def __init__(self, name):
                          '''Doc - __init__ Constructor'''
                          self.n_name = name        
                  
                      def show(self, n1, n2):
                          '''Doc - Inside Show'''
                          print self.n_name
                          print 'Sum = ', (n1 + n2)
                  
                      def __del__(self):
                          print 'Destructor Deleting object - ', self.n_name
                  
                  p=Person('Jay')
                  p.show(2, 3)
                  print p.__doc__
                  print p.__init__.__doc__
                  print p.show.__doc__
                  

                  输出:

                  Jay

                  Sum = 5

                  Doc - Inside Class

                  Doc - __init__ Constructor

                  Doc - Inside Show

                  Destructor Deleting object - Jay

                  【讨论】:

                  • 我不知道是不是只有我一个人,但是阅读这段代码有点混乱。可能是因为我还是个Python新手,idk。
                  • 我不清楚 doc 的事情。它会拉动文档吗?如果我这样做:'''test - my doc''',我可以使用:print.p.__test__?还是 doc 是一个特定的关键字?
                  • @Thomas doc 是记录详细信息的关键字。三引号用于记录文档,文档是可选实体。
                  【解决方案11】:

                  这里,这家伙写得很好很简单:https://www.jeffknupp.com/blog/2014/06/18/improve-your-python-python-classes-and-object-oriented-programming/

                  阅读以上链接作为参考:

                  self?那么对于所有客户来说,这个 self 参数是什么? 方法?它是什么?为什么,当然是实例!再放一个 方式,像withdraw这样的方法定义了撤回的指令 来自某个抽象客户帐户的钱。打电话 jeff.withdraw(100.0) 将这些指令放在 jeff 上使用 实例。

                  所以当我们说 defwithdraw(self, amount): 时,我们是在说,“这就是如何 您从 Customer 对象(我们称之为 self)中提取资金,并且 一个美元数字(我们称之为金额)。自我是的实例 正在调用退出的客户。那不是我做的 类比,要么。 jeff.withdraw(100.0) 只是简写 Customer.withdraw(jeff, 100.0),这是完全有效的(如果不是经常 见)代码。

                  init self 可能对其他方法有意义,但是 init 呢?当我们调用init时,我们正在创建一个对象,那么怎么可能已经有了一个self呢? Python允许我们扩展 构造对象时的自我模式,即使 它不完全适合。想象一下 jeff = Customer('Jeff Knupp', 1000.0) 等同于调用 jeff = Customer(jeff, 'Jeff 克努普', 1000.0);传入的 jeff 也是结果。

                  这就是为什么当我们调用 init 时,我们通过说来初始化对象 self.name = name 之类的东西。请记住,因为 self 是实例, 这相当于说 jeff.name = name,与 jeff.name = '杰夫克努普。同样,self.balance = balance 是一样的 作为 jeff.balance = 1000.0。在这两行之后,我们考虑 客户对象已“初始化”并可供使用。

                  小心你__init__

                  init 完成后,调用者可以正确地假设 对象已准备好使用。也就是说,在 jeff = Customer('Jeff Knupp', 1000.0),我们可以开始对 jeff 进行存款和取款; jeff 是一个完全初始化的对象。

                  【讨论】:

                    【解决方案12】:
                    1. __init__ 基本上是一个函数,一旦创建并匹配到对应的类..
                    2. self 表示将继承这些属性的对象。

                    【讨论】:

                    • 不必使用“self”关键字,它只是一个占位符。你可以使用任何词,但建议你使用 self 来帮助程序的可读性
                    【解决方案13】:

                    基本上,在同一类的多个函数中使用变量时,您需要使用“self”关键字。至于 init,它用于设置默认值,以防该类中没有其他函数被调用。

                    【讨论】:

                    • Python 中没有“self”关键字。调用第一个参数“self”只是一个约定。
                    • self 基本上用作占位符。不要求你使用self,你可以使用“eeee”或“foo”或其他,它只是推荐给其他程序员阅读你的代码
                    【解决方案14】:

                    我自己无法理解这一点。即使在阅读了这里的答案之后。

                    要正确理解 __init__ 方法,您需要了解 self.

                    self参数

                    __init__ 方法接受的参数是:

                    def __init__(self, arg1, arg2):
                    

                    但我们实际上只传递了两个参数:

                    instance = OurClass('arg1', 'arg2')
                    

                    额外的参数从何而来?

                    当我们访问对象的属性时,我们通过名称(或通过引用)来访问。这里的实例是对我们的新对象的引用。我们使用 instance.printargs 访问实例对象的 printargs 方法。

                    为了从__init__ 方法中访问对象属性,我们需要对该对象的引用。

                    每当调用一个方法时,对主对象的引用都会作为第一个参数传递。按照惯例,您总是将这个第一个参数调用到您的方法中。

                    这意味着在__init__ 方法中我们可以做到:

                    self.arg1 = arg1
                    self.arg2 = arg2
                    

                    我们在这里设置对象的属性。您可以通过执行以下操作来验证这一点:

                    instance = OurClass('arg1', 'arg2')
                    print instance.arg1
                    arg1
                    

                    像这样的值被称为对象属性。 这里__init__ 方法设置实例的arg1 和arg2 属性。

                    来源:http://www.voidspace.org.uk/python/articles/OOP.shtml#the-init-method

                    【讨论】:

                      【解决方案15】:

                      __init__ 确实像构造函数。如果您希望它们表现为非静态方法,则需要将“self”作为第一个参数传递给任何类函数。 “self”是您的类的实例变量。

                      【讨论】:

                      • 'self' 定义一个方法是否是静态的!哇,这让这个 java 家伙大开眼界。
                      【解决方案16】:

                      请注意,self 实际上可以是任何有效的 Python 标识符。例如,我们可以从 Chris B 的示例中轻松编写:

                      class A(object):
                          def __init__(foo):
                              foo.x = 'Hello'
                      
                          def method_a(bar, foo):
                              print bar.x + ' ' + foo
                      

                      它的工作原理完全相同。但是建议使用 self ,因为其他 python 用户会更容易识别它。

                      【讨论】:

                      • 我同意推荐 self 代替 foo,帮助其他程序员查看代码
                      【解决方案17】:

                      'self' 是对类实例的引用

                      class foo:
                          def bar(self):
                                  print "hi"
                      

                      现在我们可以创建一个 foo 的实例并调用它的方法,在这种情况下,self 参数是由 Python 添加的:

                      f = foo()
                      f.bar()
                      

                      但如果方法调用不在类实例的上下文中,也可以传入,下面的代码做同样的事情

                      f = foo()
                      foo.bar(f)
                      

                      有趣的是,变量名“self”只是一个约定。下面的定义将完全一样。虽然说它是非常严格的约定,应该始终遵循,但它确实说明了语言的灵活性

                      class foo:
                          def bar(s):
                                  print "hi"
                      

                      【讨论】:

                      • 为什么这说明了语言的灵活性?它只是说您可以为变量提供您选择的任何合法名称。这与任何其他编程语言有什么不同?
                      • 正如我在回答中所写的,“bar”只是一个函数,其中提供了一个类实例作为第一个参数。因此,虽然“bar”被定义为绑定到“foo”的方法,但它也可以使用其他类的实例来调用。这不是方法和“this”在 Java 中的工作方式,尽管我想你看到它们是相同的概念、函数​​和一些实例上下文(实例上下文是 Python 中的第一个参数,而 Java 中的“this”是) . 也许您现在可以看到我所指的语言的灵活性?
                      • 是的,这确实显示了语言的灵活性。你表达答案的方式似乎是在说你可以将“self”变量称为其他东西(如s)这一事实显示了python的灵活性。
                      【解决方案18】:

                      在这段代码中:

                      class A(object):
                          def __init__(self):
                              self.x = 'Hello'
                      
                          def method_a(self, foo):
                              print self.x + ' ' + foo
                      

                      ...self 变量表示对象本身的实例。大多数面向对象的语言将此作为隐藏参数传递给定义在对象上的方法。 Python 没有。您必须明确声明它。当您创建A 类的实例并调用其方法时,它将自动传递,如...

                      a = A()               # We do not pass any argument to the __init__ method
                      a.method_a('Sailor!') # We only pass a single argument
                      

                      __init__ 方法大致代表 Python 中的构造函数。当您调用A() 时,Python 会为您创建一个对象,并将其作为第一个参数传递给__init__ 方法。任何其他参数(例如,A(24, 'Hello'))也将作为参数传递——在这种情况下会引发异常,因为构造函数不期望它们。

                      【讨论】:

                      • 如果您将x = 'Hello' 放在 init 之外但放在类中会怎样?是像java一样,还是变成了一个只初始化一次的静态变量?
                      • 它就像一个静态变量。它只初始化一次,可通过A.xa.x 获得。请注意,在特定类上覆盖它不会影响基类,因此 A.x = 'foo'; a.x = 'bar'; print a.x; print A.x 将打印 bar 然后 foo
                      • 值得指出的是,第一个参数不一定要称为self,它只是按照惯例。
                      • 类声明中object的意义何在?我注意到有些课程有这个,有些没有
                      • @Chris 这是为了兼容 Python 2。在 Python 3 中,不需要显式地从 object 继承,因为它是默认发生的。
                      猜你喜欢
                      • 2022-12-08
                      • 1970-01-01
                      • 2016-11-29
                      • 1970-01-01
                      • 2019-04-21
                      • 1970-01-01
                      相关资源
                      最近更新 更多