关于oop:python __init__ 和 self如何理解 ?

Python __init__ and self what do they do?

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

方法如下:

1
2
3
4
def method(self, blah):
    def __init__(?):
        ....
    ....

self是做什么的?这意味着什么?这是强制性的吗?

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

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


在本代码中:

1
2
3
4
5
6
class A(object):
    def __init__(self):
        self.x = 'Hello'

    def method_a(self, foo):
        print self.x + ' ' + foo

self变量表示对象本身的实例。大多数面向对象的语言都将其作为隐藏参数传递给对象上定义的方法;而Python则不这样做。你必须明确声明。当您创建A类的实例并调用其方法时,它将自动传递,如…

1
2
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')也将作为参数传递--在这种情况下,会引发异常,因为构造函数不期望这些参数。


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

__init__是类的构造函数。EDCOX1×2参数是指对象的实例(如C++中的EDCOX1×3)。

1
2
3
4
class Point:
    def __init__(self, x, y):
        self._x = x
        self._y = y

当为对象分配内存时,调用__init__方法:

1
x = Point(1,2)

如果要将值与对象一起持久化,则必须在对象方法中使用self参数。例如,如果您这样实现__init__方法:

1
2
3
4
class Point:
    def __init__(self, x, y):
        _x = x
        _y = y

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


一个简单的例子

希望它能有所帮助,下面是一个简单的示例,我用来理解类内声明的变量与__init__函数内声明的变量之间的区别:

1
2
3
4
5
6
7
8
9
10
class MyClass(object):
     i = 123
     def __init__(self):
         self.i = 345

a = MyClass()
print a.i
345
print MyClass.i
123


简而言之:

  • 顾名思义,self指的是它自己——调用了方法的对象。也就是说,如果有n个对象调用该方法,那么self.a将为每个n个对象引用该变量的单独实例。假设每个对象的变量A的n个副本
  • __init__是其他OOP语言(如C++/Java)中的构造函数。其基本思想是,它是一个特殊的方法,在创建该类的对象时自动调用。

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


    尝试此代码。希望它能帮助像我这样的C程序员学习py。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #! /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


    我自己也难以忍受。即使在阅读了这里的答案之后。

    要正确理解__init__方法,你需要了解自我。

    自参数

    __init__方法接受的参数是:

    1
    def __init__(self, arg1, arg2):

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

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

    额外的争论来自哪里?

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

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

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

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

    1
    2
    self.arg1 = arg1
    self.arg2 = arg2

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

    1
    2
    3
    instance = OurClass('arg1', 'arg2')
    print instance.arg1
    arg1

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

    来源:http://www.voidspace.org.uk/python/articles/oop.shtml init方法


    注意,self实际上可以是任何有效的python标识符。例如,我们可以很容易地从Chris B的例子中写:

    1
    2
    3
    4
    5
    6
    class A(object):
        def __init__(foo):
            foo.x = 'Hello'

        def method_a(bar, foo):
            print bar.x + ' ' + foo

    它的工作原理完全一样。然而,建议使用Self,因为其他的Python会更容易识别它。


  • __init__基本上是一个函数,一旦创建并匹配到相应的类,它将"初始化"/"激活"特定对象的类属性。
  • self表示将继承这些属性的对象。

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


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

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

    1
    2
    3
    4
    5
    6
    class MyClass:
       """A simple example class"""
        i = 12345

        def f(self):
            return 'hello world'

    那么,MyClass.iMyClass.f是有效的属性引用,分别返回整数和函数对象。类属性也可以分配给,因此您可以通过分配更改MyClass.i的值。__doc__也是一个有效的属性,返回属于该类的docstring:"一个简单的示例类"。

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

    1
    x = MyClass()

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

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

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

    1
    x = MyClass()

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

    1
    2
    3
    4
    5
    6
    7
    class Complex:
        def __init__(self, realpart, imagpart):
            self.r = realpart
            self.i = imagpart

    x = Complex(3.0, -4.5)
    x.r, x.i

    从最终帮助我的官方文件中获取。

    这是我的例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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 :)")

    创建类清单实例时:

    1
    purchase = Bill(5,6,7)

    你得到:

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


    "self"是对类实例的引用

    1
    2
    3
    class foo:
        def bar(self):
                print"hi"

    现在我们可以创建一个foo实例并对其调用方法,在这种情况下,python会添加self参数:

    1
    2
    f = foo()
    f.bar()

    但是,如果方法调用不在类实例的上下文中,也可以传入它,下面的代码执行相同的操作

    1
    2
    f = foo()
    foo.bar(f)

    有趣的是,变量名'self'只是一个约定。下面的定义将完全相同。虽然它是一种非常强的惯例,应该一直遵循,但它确实说明了语言的灵活性。

    1
    2
    3
    class foo:
        def bar(s):
                print"hi"


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    # 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()

    在本代码中:

    1
    2
    3
    4
    5
    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表示实例化对象。

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

    上述陈述的结果如下:

    1
    I am a cat and I am called Kitty

    只是一个问题的演示。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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()
    1
    2
    3
    4
    5
    6
    $ 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


    Python __init__ and self what do they do?

    What does self do? What is it meant to be? Is it mandatory?

    What does the __init__ method do? Why is it necessary? (etc.)

    给出的示例不正确,因此让我基于它创建一个正确的示例:

    1
    2
    3
    4
    5
    6
    7
    class SomeObject(object):

        def __init__(self, blah):
            self.blah = blah

        def method(self):
            return self.blah

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

    1
    an_object = SomeObject('blah')

    self论点是SomeObject的实例,将分配给an_object

    稍后,我们可能希望对此对象调用一个方法:

    1
    an_object.method()

    进行点式查找,即an_object.method将实例绑定到函数的一个实例,而方法(如上所述)现在是一个"绑定"方法,这意味着我们不需要显式地将实例传递到方法调用。

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

    根据惯例,隐式传递的self参数称为self。我们可以使用任何其他合法的python名称,但是如果您将其更改为其他名称,其他python程序员很可能会对您进行tarred和feathered。

    __init__是一种特殊的方法,记录在python数据模型文档中。它在创建实例后立即调用(通常通过__new__—尽管不需要__new__,除非您要对不可变的数据类型进行子类化)。


    What does self do? What is it meant to be? Is it mandatory?

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

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

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

    What does the init method do? Why is it necessary? (etc.)

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


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

    请阅读以上链接作为对此的参考:

    self? So what's with that self parameter to all of the Customer
    methods? What is it? Why, it's the instance, of course! Put another
    way, a method like withdraw defines the instructions for withdrawing
    money from some abstract customer's account. Calling
    jeff.withdraw(100.0) puts those instructions to use on the jeff
    instance.

    So when we say def withdraw(self, amount):, we're saying,"here's how
    you withdraw money from a Customer object (which we'll call self) and
    a dollar figure (which we'll call amount). self is the instance of the
    Customer that withdraw is being called on. That's not me making
    analogies, either. jeff.withdraw(100.0) is just shorthand for
    Customer.withdraw(jeff, 100.0), which is perfectly valid (if not often
    seen) code.

    init self may make sense for other methods, but what about init? When we call init, we're in the process of creating an object, so how can there already be a self? Python allows us to extend
    the self pattern to when objects are constructed as well, even though
    it doesn't exactly fit. Just imagine that jeff = Customer('Jeff
    Knupp', 1000.0) is the same as calling jeff = Customer(jeff, 'Jeff
    Knupp', 1000.0); the jeff that's passed in is also made the result.

    This is why when we call init, we initialize objects by saying
    things like self.name = name. Remember, since self is the instance,
    this is equivalent to saying jeff.name = name, which is the same as
    jeff.name = 'Jeff Knupp. Similarly, self.balance = balance is the same
    as jeff.balance = 1000.0. After these two lines, we consider the
    Customer object"initialized" and ready for use.

    Be careful what you __init__

    After init has finished, the caller can rightly assume that the
    object is ready to use. That is, after jeff = Customer('Jeff Knupp',
    1000.0), we can start making deposit and withdraw calls on jeff; jeff is a fully-initialized object.