转自:http://www.programiz.com/article/python-self-why

If you have been programming in Python (in object oriented way of course) for some time, I'm sure you have come across methods that have self as their first parameter. It may seem odd, especially to programmers coming from other languages, that this is done explicitly every single time we define a method. As The Zen of Python goes, "Explicit is better than implicit".

So, why do we need to do this? Let's take a simple example to begin with. We have a Point class which defines a method distance to calculate the distance from origin.


class Point(object):
def __init__(self,x = 0,y = 0):
self.x = x
self.y = y def distance(self):
"""Find distance from origin"""
return (self.x**2 + self.y**2) ** 0.5

Let us now instantiate this class and find the distance.


>>> p1 = Point(6,8)
>>> p1.distance()
10.0

In the above example, __init__() defines three parameters but we just passed two (6 and 8). Similarly distance() requires one but zero arguments were passed. Why is Python not complaining about this argument number mismatch?

What Happens Internally?

Let me first clarify that Point.distance and p1.distance in the above example are a bit different.


>>> type(Point.distance)
<class 'function'>
>>> type(p1.distance)
<class 'method'>

We can see that the first one is a function and second, a method. A peculiar thing about methods (in Python) is that the object itself is passed on as the first argument to the corresponding function. In the case of the above example, the method call p1.distance() is actually equivalent toPoint.distance(p1). Generally, when we call a method with some arguments, the corresponding class function is called by placing the method's object before the first argument. So, anything likeobj.meth(args) becomes Class.meth(obj, args). The calling process is automatic while the receiving process is not (its explicit).

This is the reason the first parameter of a function in class must be the object itself. Writing this parameter as self is merely a convention. It is not a keyword and has no special meaning in Python. We could use other names (like this) but I strongly suggest you not to. Using names other than self is frowned upon by most developers and degrades the readability of the code ("Readability counts").

Self Can Be Avoided

By now you are clear that the object (instance) itself is passed along as the first argument, automatically. This implicit behavior can be avoided by making a method, static. Consider the following simple example.


class A(object): @staticmethod
def stat_meth():
print("Look no self was passed")

Here, @staticmethod is a function decorator which makes stat_meth() static. Let us instantiate this class and call the method.


>>> a = A()
>>> a.stat_meth()
Look no self was passed

From the above example, we are clear that the implicit behavior of passing the object as the first argument was avoided using static method. All in all, static methods behave like our plain old functions.


>>> type(A.stat_meth)
<class 'function'>
>>> type(a.stat_meth)
<class 'function'>

Self Is Here To Stay

The explicit self is not unique to Python. This idea was borrowed from Modula-3. Following is a use case where it becomes helpful.

There is no explicit variable declaration in Python. They spring into action on the first assignment. The use of self makes it easier to distinguish between instance attributes (and methods) from local variables. In, the first example self.x is an instance attribute whereas x is a local variable. They are not the same and lie in different namespaces.

Many have proposed to make self a keyword in Python, like this in C++ and Java. This would eliminate the redundant use of explicit self from the formal parameter list in methods. While this idea seems promising, it's not going to happen. At least not in the near future. The main reason is backward compatibility. Here is a blog from the creator of Python himself explaining why the explicit self has to stay.

__init__() is not a constructor

One important conclusion that can be drawn from the information so far is that, __init__() is not a constructor. Many na?ve Python programmers get confused with it since __init__() gets called when we create an object. A closer inspection will reveal that the first parameter in __init__() is the object itself (object already exists). The function __init__() is called immediately after the object is created and is used to initialize it.

Technically speaking, constructor is a method which creates the object itself. In Python, this method is __new__(). A common signature of this method is


__new__(cls, *args, **kwargs)

When __new__() is called, the class itself is passed as the first argument automatically. This is what the cls in above signature is for. Again, like self, cls is just a naming convention. Furthermore,*args and **kwargs are used to take arbitary number of arguments during method calls in Python.

Some important things to remember when implementing __new__() are:

  • __new__() is always called before __init__().
  • First argument is the class itself which is passed implicitly.
  • Always return a valid object from __new__(). Not mandatory, but thats the whole point.

Let's take a look at an example to be crystal clear.


class Point(object): def __new__(cls,*args,**kwargs):
print("From new")
print(cls)
print(args)
print(kwargs) # create our object and return it
obj = super().__new__(cls)
return obj def __init__(self,x = 0,y = 0):
print("From init")
self.x = x
self.y = y

Now, let's now instantiate it.


>>> p2 = Point(3,4)
From new
<class '__main__.Point'>
(3, 4)
{}
From init

This example illustrates that __new__() is called before __init__(). We can also see that the parameter cls in __new__() is the class itself (Point). Finally, the object is created by calling the__new__() method on object base class. In Python, object is the base class from which all other classes are derived. In the above example, we have done this using super().

Use __new__ or __init__?

You might have seen __init__() very often but the use of __new__() is rare. This is because most of the time you don't need to override it. Generally, __init__() is used to initialize a newly created object while __new__() is used to control the way an object is created. We can also use __new__()to initialize attributes of an object, but logically it should be inside __init__(). One practical use of__new__() however, could be to restrict the number of objects created from a class.

Suppose we wanted a class SqPoint for creating instances to represent the four vertices of a square. We can inherit from our previous class Point (first example in this article) and use__new__() to implement this restriction. Here is an example to restrict a class to have only four instances.


class SqPoint(Point):
MAX_Inst = 4
Inst_created = 0 def __new__(cls,*args,**kwargs):
if (cls.Inst_created >= cls.MAX_Inst):
raise ValueError("Cannot create more objects")
cls.Inst_created += 1
return super().__new__(cls)

A sample run.


>>> p1 = SqPoint(0,0)
>>> p2 = SqPoint(1,0)
>>> p3 = SqPoint(1,1)
>>> p4 = SqPoint(0,1)
>>>
>>> p5 = SqPoint(2,2)
Traceback (most recent call last):
...
ValueError: Cannot create more objects

The Story of self Parameter in Python, Demystified的更多相关文章

  1. 替换空格(C++和Python 实现)

    (说明:本博客中的题目.题目详细说明及参考代码均摘自 “何海涛<剑指Offer:名企面试官精讲典型编程题>2012年”) 题目 请实现一个函数,把字符串中的每个空格替换为 "%2 ...

  2. Python进阶-函数默认参数

    Python进阶-函数默认参数 写在前面 如非特别说明,下文均基于Python3 一.默认参数 python为了简化函数的调用,提供了默认参数机制: def pow(x, n = 2): r = 1 ...

  3. sqlmap使用手册

    转自:http://hi.baidu.com/xkill001/item/e6c8cd2f6e5b0a91b7326386 SQLMAP 注射工具用法 1 . 介绍1.1 要求 1.2 网应用情节 1 ...

  4. 小白眼中的AI之~Numpy基础

      周末码一文,明天见矩阵- 其实Numpy之类的单讲特别没意思,但不稍微说下后面说实际应用又不行,所以大家就练练手吧 代码裤子: https://github.com/lotapp/BaseCode ...

  5. sqlmap原理及使用方法

    1 . 介绍1.1 要求 1.2 网应用情节 1.3 SQL 射入技术 1.4 特点 1.5 下载和更新sqlmap 1.6 执照 2 . 用法2.1 帮助 2.2 目标URL 2.3 目标URL 和 ...

  6. Robot Framework接口测试(1)

    RF是做接口测试的一个非常方便的工具,我们只需要写好发送报文的脚本,就可以灵活的对接口进行测试. 做接口测试我们需要做如下工作: 1.拼接发送的报文 2.发送请求的方法 3.对结果进行判断 我们先按步 ...

  7. Allure-pytest功能特性介绍

    前言 Allure框架是一个灵活的轻量级多语言测试报告工具,它不仅以web的方式展示了简介的测试结果,而且允许参与开发过程的每个人从日常执行的测试中最大限度的提取有用信息从dev/qa的角度来看,Al ...

  8. Pytest系列(19)- 我们需要掌握的allure特性

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 前面我们介绍了allure的 ...

  9. pytest(12)-Allure常用特性allure.attach、allure.step、fixture、environment、categories

    上一篇文章pytest Allure生成测试报告我们学习了Allure中的一些特性,接下来继续学习其他常用的特性. allure.attach allure.attach用于在测试报告中添加附件,补充 ...

随机推荐

  1. MVC使用Google OAuth[OWIN]注意事項

    1.前提條件,申請一個client id,頁面:https://console.developers.google.com/ 2.添加連接域名,javascript那欄位為域名即可,另一欄需要加上具體 ...

  2. 附加题-stack的理解

    这次的附加题推荐的博客是http://www.ruanyifeng.com/blog/2013/11/stack.html阮一峰的,感觉讲的深入浅出,比较适合对计算机刚刚接触的人: 下面谈谈感想: 这 ...

  3. 现代程序设计 homework-09

    现代程序设计 homework-09 这次作业是要求将homework-02做成一个可演示的应用,目的是为了让用户看到程序的计算步骤以及中间结果. 借此机会也学了一下JavaScript,感觉总结的地 ...

  4. New full duplex HTTP tunnel implementation (client and server)

    https://issues.jboss.org/browse/NETTY-246?page=com.atlassian.jirafisheyeplugin:fisheye-issuepanel —— ...

  5. ActiveMQ学习笔记(二) JMS与Spring

    上文可见,JMS Native API使用起来不是特别方便.好在Spring提供了很好的JMS支持. (一)配置ConnectionFactory 如果使用连接池的话,不要忘记activemq-poo ...

  6. iOS开发代码规范

    1.关于命名 1.1统一要求 含义清楚, 尽量做到不需要注释也能了解其作用,若做不到,就加注释 使用全称不使用缩写 1.2类的命名 大驼峰式命名:每一个单词的首字母都采用大写字母例子: MFHomeP ...

  7. C#学习笔记(十三):I/O操作

    C#的IO操作主要是针对文件夹和文件的读取和写入操作,下面我们来学习一下相关操作的类. 获取文件信息 Directory和DirectoryInfo 两个类的功能基本相同,区别如下: 前者继承Syst ...

  8. .Net 代码安全保护产品DNGuard HVM使用

    前辈人物写的程序啊! 官方网站:http://www.dnguard.net/index.aspx 官方博客:http://www.cnblogs.com/rick/ (很久没更新了) 原文http: ...

  9. list对象排序

    在数据库中查出来的列表list中,往往需要对不同的字段重新排序,一般的做法都是使用排序的字段,重新到数据库中查询.如果不到数据库查询,直接在第一次查出来的list中排序,无疑会提高系统的性能. 只要把 ...

  10. 从零开始学android开发-View的setOnClickListener的添加方法

    1)第一种,也是最长见的添加方法(一下都以Button为例) Button btn = (Button) findViewById(R.id.myButton); btn .setOnClickLis ...