Python中:self和__init__的含义 + 为何要有self和__init__

背景

回复:

我写的一些Python教程,需要的可以看看

SongShouJiong的提问:

Python中的self,__init__的含义是啥?

为何要有self,__init这些东西?

解释之前,先说几句

1.到目前为止,我虽然也已写了不算很少的python的代码,但是,还真的没有太多接触self和__init__这两个东西。

只能算是大概了解。

2.为了搞懂其含义,现学现卖,去看了些资料,然后整理出来。

其中,很可能理解有误,还请高手指正。

3.解释含义之前,先说说对于学习Python中的self和__init__等内容的态度:

个人的建议是,很多东西,等你有了需求了,再去使用,该东西才算有价值,你也才会更容易理解;

否则,暂时接触不到的话,其实可以将其放到一边,等以后遇到了再说。

否则,现在就去努力的学,态度虽好,但是由于没有相关的编程实践,即没有足够的代码的练习,对于概念的理解,必然很难深入。

因此,对于Python中的self和__init__的建议是:

如果你去写Python代码,去学习Python的过程中,在没有遇到之前,

比如像我这种,一直就没怎么编写过真正的类(Class),那么倒也是可以暂时不用太理会这些东西;

等以后需要编写类的时候,再去详细学习,了解,搞懂其含义。

4.下面的内容,算是为你,的确遇到了self,__init__,的时候,需要理解其含义的时候,提供一些参考。

5.在看下面的解释之前,你首先要对类(Class)和类的实例化的对象(Object,也称实例Instance)的概念,有所了解。

如果不了解,可以参考我总结的:

【整理】面向对象的基础知识:类Class,对象(Object),实例(Instance)


python中self和__init__的含义 + 为何要有self和__init__

Python中的self

在Python中的类Class的代码中,常看到函数中的第一个参数,都是self。

以及Class中的函数里面,访问对应的变量(读取或者写入),以及调用对应的函数时,都是

self.valueName

self.function()

的形式。

下面就来解释一下self的含义:

Python中self的含义

self,英文单词意思很明显,表示自己,本身。

此处有几种潜在含义:

1.这里的自己,指的是,实例Instance本身。

2.同时, 由于说到“自己”这个词,都是和相对而言的“其他”而说的。

而此处的其他,指的是,类Class,和其他变量,比如局部变量,全局变量等。

此处的self,是个对象,Object。

是当前类的实例。

因此,对应的

self.valueName

self.function()

中的

valueName:表示self对象,即实例的变量。与其他的,Class的变量,全局的变量,局部的变量,是相对应的。

function:表示是调用的是self对象,即实例的函数。与其他的全局的函数,是相对应的。

Python中为何要有self

上面其实已经基本上说清楚了,为何需要有self。

那就是:

在类的代码(函数)中,需要访问当前的实例中的变量和函数的,即,访问Instance中的:

  • 对应的变量(property):Instance.ProperyNam,去读取之前的值和写入新的值

  • 调用对应函数(function):Instance.function(),即执行对应的动作

-> 而需要访问实例的变量和调用实例的函数,当然需要对应的实例Instance对象本身

-> 而Python中就规定好了,函数的第一个参数,就必须是实例对象本身,并且建议,约定俗成,把其名字写为self

-> 所以,我们需要self(需要用到self)

而如果没有用到self,即代码中,去掉self后,那种写法所使用到的变量,实际上不是你所希望的,不是真正的实例中的变量和函数,而是的访问到了其他部分的变量和函数了。

甚至会由于没有合适的初始化实例变量,而导致后续无法访问的错误。

下面,就通过代码,来演示,如果去掉self,或者没有合理的使用self,会出现哪些错误。

如果没有在__init__中初始化对应的实例变量的话,导致后续引用实例变量会出错

如下代码,完整的演示了,如果没有在类Class的最初的__init__函数中,正确的初始化实例变量,则会导致后续没有变量可用,因而出现AttributeError的错误:

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------------------------------------
Function:
【整理】Python中:self和init__的含义 + 为何要有self和__init__
http://www.crifan.com/summary_the_meaning_of_self_and___init___in_python_and_why_need_them

Author:     Crifan
Verison:    2012-11-27
-------------------------------------------------------------------------------
"""

#注:此处全局的变量名,写成name,只是为了演示而用
#实际上,好的编程风格,应该写成gName之类的名字,以表示该变量是Global的变量
name = "whole global name";

class Person:
    def __init__(self, newPersionName):
        #self.name = newPersionName;

        #1.如果此处不写成self.name
        #那么此处的name,只是__init__函数中的局部临时变量name而已
        #和全局中的name,没有半毛钱关系
        name = newPersionName;

        #此处只是为了代码演示,而使用了局部变量name,
        #不过需要注意的是,此处很明显,由于接下来的代码也没有利用到此处的局部变量name
        #则就导致了,此处的name变量,实际上被浪费了,根本没有利用到

    def sayYourName(self):
        #此处由于找不到实例中的name变量,所以会报错:
        #AttributeError: Person instance has no attribute 'name'
        print 'My name is %s'%(self.name);

def selfAndInitDemo():
    persionInstance = Person("crifan");
    persionInstance.sayYourName();

###############################################################################
if __name__=="__main__":
    selfAndInitDemo();

从上述代码可见,由于在类的初始化(实例化)的__init__函数中,没有给self.name设置值,使得实例中,根本没有name这个变量,导致后续再去访问self.name,就会出现AttributeError的错误了。

对应的,如果写成self.name,则意思就正确了,就是初始化的时候,给实例中新增加,并且正常设置了正确的值newPersionName了,所以后续再去通过self.name,就可以访问到,当前实例中正确的变量name了。

相应的正确写法的代码如下:

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------------------------------------
Function:
【整理】Python中:self和init__的含义 + 为何要有self和__init__
http://www.crifan.com/summary_the_meaning_of_self_and___init___in_python_and_why_need_them

Author:     Crifan
Verison:    2012-11-27
-------------------------------------------------------------------------------
"""

#注:此处全局的变量名,写成name,只是为了演示而用
#实际上,好的编程风格,应该写成gName之类的名字,以表示该变量是Global的变量
name = "whole global name";

class Person:
    def __init__(self, newPersionName):
        #此处正确的,通过访问self.name的形式,实现了:
        #1.给实例中,增加了name变量
        #2.并且给name赋了初值,为newPersionName
        self.name = newPersionName;

    def sayYourName(self):
        #此处由于开始正确的初始化了self对象,使得其中有了name变量,所以此处可以正确访问了name值了,可以正确的输出了:
        #My name is crifan
        print 'My name is %s'%(self.name);

def selfAndInitDemo():
    persionInstance = Person("crifan");
    persionInstance.sayYourName();

###############################################################################
if __name__=="__main__":
    selfAndInitDemo();

在函数中,使用对应的变量,虽然代码是可以运行的,但是实际上却是使用的,不是实例中的变量

有时候,虽然你写的代码,可以运行,但是使用到的变量,由于没有加self,实际上是用到的不是实例的变量,而是其他的变量。

此类问题,主要和Python中的变量的作用域有关,但是此处例子中,也和是否使用self有关:

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------------------------------------
Function:
【整理】Python中:self和init__的含义 + 为何要有self和__init__
http://www.crifan.com/summary_the_meaning_of_self_and___init___in_python_and_why_need_them

Author:     Crifan
Verison:    2012-11-27
-------------------------------------------------------------------------------
"""

#注:此处全局的变量名,写成name,只是为了演示而用
#实际上,好的编程风格,应该写成gName之类的名字,以表示该变量是Global的变量
name = "whole global name";

class Person:
    name = "class global name"

    def __init__(self, newPersionName):
        #self.name = newPersionName;

        #此处,没有使用self.name
        #而使得此处的name,实际上仍是局部变量name
        #虽然此处赋值了,但是后面没有被利用到,属于被浪费了的局部变量name
        name = newPersionName;

    def sayYourName(self):
        #此处,之所以没有像之前一样出现:
        #AttributeError: Person instance has no attribute 'name'
        #那是因为,虽然当前的实例self中,没有在__init__中初始化对应的name变量,实例self中没有对应的name变量
        #但是由于实例所对应的类Person,有对应的name变量,所以也是可以正常执行代码的
        #对应的,此处的self.name,实际上是Person.name
        print 'My name is %s'%(self.name); # -> class global name
        print 'name within class Person is actually the global name: %s'%(name); #-> whole global name
        print "only access Person's name via Person.name=%s"%(Person.name); # -> class global name

def selfAndInitDemo():
    persionInstance = Person("crifan");
    persionInstance.sayYourName();
    print "whole global name is %s"%(name); # -> whole global name

###############################################################################
if __name__=="__main__":
    selfAndInitDemo();

其中,可见,此处开始__init__中,没有给self实例初始化对应的name

而后面的函数sayYourName中,虽然可以调用到self.name而没有出现AttributeError错误

但是实际上此处的值,不是所期望的,传入的name,即"crifan",而是类中的name的值,即"class global name"。

关于Python中变量的作用域的详细解释,可参考:

【整理】Python中变量的作用域(variable scope)

Python中的__init__

Python中,常会看到,很多类中,都有一个__init__函数。

下面就来解释一下,__init__的含义。

Python中__init__的含义

首先来看init单词本身,其含义是 初始化。

而__init__的含义,也如同其单词本意一样,用来初始化。

但是给谁初始化呢?

很明显,是给对应的类Class本身,去初始化。

Python中为何要有__init__

我的理解是,__init__的出现,主要有两方面的作用:

一般常见的初始化,我的理解,可能主要有两方面:

支持带参数的类的初始化

这个用法,感觉就像,其他语言中的,对于Class初始化时,可以运行传递不同的参数一样;

用代码演示如下:

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------------------------------------
Function:
【整理】Python中:self和init__的含义 + 为何要有self和__init__
http://www.crifan.com/summary_the_meaning_of_self_and___init___in_python_and_why_need_them

Author:     Crifan
Verison:    2012-11-27
-------------------------------------------------------------------------------
"""

class Person:
    def __init__(self, newPersionName):
        #在开始初始化新的类Class的示例Instance的时候,给对应的,不同的Instance,设置不同的人名(Person name)
        self.name = newPersionName;

    def sayYourName(self):
        #不同的Person的示例,调用同样的方法的时候,说出自己的名字,结果都是对应着自己的,各自不同的名字
        print 'My name is %s'%(self.name); #My name is crifan

def initDemo():
    persionInstance = Person("crifan");
    persionInstance.sayYourName();

###############################################################################
if __name__=="__main__":
    initDemo();

其中,就是针对Person这个类,

不同的示例,在初始化的时候,都传递一个对应的参数,这样不同的Person,就都有了自己的不同的名字了。

这个,至少看起来,有点类似于,其他语言中的,传递特定参数去对类进行初始化。

实现类本身相关内容的初始化

当一个Class,稍微复杂一点的时候,或者内部函数需要用得到的时候,往往都需要在,别人实例化你这个类之前,使用你这个类之前,做一些基本的,与自己的类有关的,初始化方面的工作。

而这部分工作,往往就放到__init__函数中去了。

换句话说,你要用人家的类(中的变量和函数)之前,总要给人家一个机会,做点准备工作,然后才能为你服务吧。

这个概念,相对还是很好理解的,就不多赘述。

演示代码就不用了,因为上面的代码,也可以算是这方面的例子了,不同的人,应该有不同的名字,而给不同的人设置不同的名字,也是需要在调用sayYourName之前,就先初始化好的。

参考资料

1. 使用__init__方法

2. 了解何时去使用 self 和 __init__

3.Python 'self' explained

4. Python __init__ and self what do they do?

Python中:self和__init__的含义 + 为何要有self和__init__的更多相关文章

  1. 转载--------Python中:self和__init__的含义 + 为何要有self和__init__

    背景 回复:我写的一些Python教程,需要的可以看看,中SongShouJiong的提问: Python中的self,__init__的含义是啥?为何要有self,__init这些东西? 解释之前, ...

  2. Python中的__name__和__main__含义详解

    1背景 在写Python代码和看Python代码时,我们常常可以看到这样的代码: ? 1 2 3 4 5 def main():     ......   if __name == "__m ...

  3. Python中 *args 和 **kwargs 的含义?

    答:在python中,*args和**kwargs通常使用在函数定义里.*args 和 **kwargs 都允许你给函数传不定数量的参数,即使在定义函数的时候不知道调用者会传递几个参数.ps: *ar ...

  4. Python中的self和init

    From: https://www.crifan.com/summary_the_meaning_of_self_and___init___in_python_and_why_need_them/ 背 ...

  5. Python中元类

    元类(metaclass) 简单地说,元类就是一个能创建类的类,而类class 是由type创建的,class可以创建对象 type与object的关系详见:python中type和object 1. ...

  6. python中的运算符及表达式及常用内置函数

    知识内容: 1.运算符与表达式 2.for\while初步了解 3.常用内置函数 一.运算符与表达式 python与其他语言一样支持大多数算数运算符.关系运算符.逻辑运算符以及位运算符,并且有和大多数 ...

  7. 如何将xml转为python中的字典

    如何将xml转为python中的字典 import cElementTree as ElementTree class XmlListConfig(list): def __init__(self, ...

  8. Python中列表的各种方法

    列表是Python中一种常用的存储信息的方式,所以要熟练掌握列表的各种方法: 首先我们定义一个列表(name),然后练习里面的各种方法: >>> name = ["Sora ...

  9. python中包和模块的使用说明

    python中,每个py文件被称之为模块,每个具有__init__.py文件的目录被称为包.只要模块或者包所在的目录在sys.path中,就可以使用import 模块或import 包来使用. 如果想 ...

随机推荐

  1. TEA encryption with 128bit key

    If anyone needs some basic encryption in software, here's one solution. This TEA implementation fits ...

  2. arcgis api for silverlight使用google map等多个在线地图

    原文 http://blog.csdn.net/leesmn/article/details/6820245 无可否认,google map实在是很漂亮.可惜对于使用arcgis api for si ...

  3. 转:基础总结篇之一:Activity生命周期

    熟悉javaEE的朋友们都了解servlet技术,我们想要实现一个自己的servlet,需要继承相应的基类,重写它的方法,这些方法会在合适的时间被servlet容器调用.其实android中的Acti ...

  4. python连续爬取多个网页的图片分别保存到不同的文件夹

      python连续爬取多个网页的图片分别保存到不同的文件夹 作者:vpoet mail:vpoet_sir@163.com #coding:utf-8 import urllib import ur ...

  5. Python递归函数与斐波那契数列

    定义:在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数. 阶乘实例 n = int(input(">>:")) def f(n): s ...

  6. Spring定时任务的几种实现(转自iteye网gong1208)

    原文地址: http://gong1208.iteye.com/blog/1773177 以下为正文: 近日项目开发中需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信息,借此机会整 ...

  7. android ANR 案例分析

    案例1:关键词:ContentResolver in AsyncTask onPostExecute, high iowait Process:com.android.email Activity:c ...

  8. 字符串和数字的全排列问题、前i位被i整除问题

    // 全排列问题.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> using names ...

  9. [Java Web]Struts2解决中文乱码问题

    1.设置struts的字符编码,能够在struts.xml中添加下面代码: <constant name="struts.i18n.encoding" value=" ...

  10. UMl概述(转)

    1. UML的组成 UML由视图(View).图(Diagram).模型元素(Model Element)和通用机制(General Mechanism)等几个部分组成. a) 视图(View): 是 ...