深入浅析python 中的self和cls的区别


Posted in Python onJune 20, 2020

python 中的self和cls

一句话描述:self是类(Class)实例化对象,cls就是类(或子类)本身,取决于调用的是那个类。
@staticmethod 属于静态方法装饰器,@classmethod属于类方法装饰器。我们需要从声明和使用两个方面来理解。

详细介绍

一般来说,要使用某个类的方法,需要先⚠️实例化一个对象再调用方法。而使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁。?

首先定义一个类A,类A中有三个函数,foo1为静态函数,用@staticmethod装饰器装饰,这种方法与类有某种关系但不需要使用到实例或者类来参与。

class A(object):
 a = 'a'
 @staticmethod
 def foo1(name):
 print('hello', name, A.a)
 def foo2(self, name):
 print('hello', name, self.a)
 @classmethod
 def foo3(cls, name):
 print('hello', name, cls.a)
class B(A):
 a = 'b'
 @staticmethod
 def foo1(name):
 print('hello', name, B.a)
 def foo2(self, name):
 print('subclass B')
 print('hello', name, self.a)
 @classmethod
 def foo3(cls, name):
 print('hello', name, cls.a)

如下两种方法都可以正常输出,也就是说

既可以作为类的方法使用,也可以作为类的实例的方法使用。

a = A()
b = B()
a.foo1("小熊猫") # hello 小熊猫 
A.foo1("小熊猫") # hello 小熊猫 
b.foo1("大熊猫") # subclass B, hello 大熊猫 b
B.foo1("大熊猫") # subclass B, hello 大熊猫 b

foo2为正常的函数,是类的实例的函数,调用方式如下。

实参实例化对象或者类名称传入self对象,取到不同的属性和方法。

a.foo2("小熊猫") # hello 小熊猫 a
A.foo2(a, "小熊猫") # hello 小熊猫 a
A.foo2(b, "小熊猫") # hello 小熊猫 b
A.foo2(A, "小熊猫") # hello 小熊猫 a 
A.foo2(B, "小熊猫") # hello 小熊猫 b
B.foo2(a, "小熊猫") # subclass B, hello 小熊猫 a

foo3为类函数,cls作为第一个参数用来表示类本身. 在类方法中用到,类方法是只与类本身有关而与实例无关的方法。如下两种方法都可以正常输出。

可以看出,传入形参cls的值为前面的调用函数,如果再传入对象或者类名称,会报类型错误,多传了一个参数。

a.foo3("小熊猫")
A.foo3("小熊猫")
# a.foo3(a, "小熊猫") # TypeError: foo3() takes 2 positional arguments but 3 were given
# A.foo3(A, "小熊猫") # TypeError: foo3() takes 2 positional arguments but 3 were given
b.foo3("大熊猫")
B.foo3("大熊猫")

@staticmethod和@classmethod的用法

相同:

@staticmethod和@classmethod都可以直接类名.方法名()来调用

区别:

  • 从它们的使用上来看,@staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。@classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。
  • 如果在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。
  • 而@classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等,避免硬编码。
class A(object):
 a = 'a'
 @staticmethod
 def foo1(name):
 print('hello foo1', name, A.a)
 print("hello foo4 ", B.foo2(B, "小熊猫"))
 def foo2(self, name):
 print('hello foo2', name, self.a)
 @classmethod
 def foo3(cls, name):
 print('hello foo3', name, cls.a)
 print("hello foo5", cls().foo2(name))
 print("hello foo6", cls().foo1(name))
class B(A):
 a = 'b'
 @staticmethod
 def foo1(name):
 print('subclass B, hello', name, B.a)
 def foo2(self, name):
 print('subclass B, hello', name, self.a)
 @classmethod
 def foo3(cls, name):
 print('subclass B, hello', name, cls.a)

 重点应关注@staticmethod和@classmethod调用本类或其他类的函数和属性的区别

例子1:

关键看第二句 subclass B, hello 小熊猫 b,在调用 B.foo2(B, “小熊猫”) 时,执行了B类型下的foo2()方法,该方法无返回值,因此 下句输出为 hello foo4 None

a = A()
a.foo1("小熊猫")
# 输出
hello foo1 小熊猫 a
subclass B, hello 小熊猫 b
hello foo4 None

例子2:

a.foo3("小熊猫")
# 输出
hello foo3 小熊猫 a
hello foo2 小熊猫 a
hello foo5 None
hello foo1 小熊猫 a
subclass B, hello 小熊猫 b
hello foo4 None
hello foo6 None

PS:下面看下python中self和cls的区别

1、self表示一个具体的实例本身。如果用了staticmethod,那么就可以无视这个self,将这个方法当成一个普通的函数使用。

2、cls表示这个类本身。

>>> class A(object):
    def foo1(self):
      print "Hello",self
    @staticmethod
    def foo2():
      print "hello"
    @classmethod
    def foo3(cls):
      print "hello",cls

>>> a = A()
>>> a.foo1()     #最常见的调用方式,但与下面的方式相同
Hello <__main__.A object at 0x9f6abec>
>>> A.foo1(a)     #这里传入实例a,相当于普通方法的self
Hello <__main__.A object at 0x9f6abec>
>>> A.foo2()     #这里,由于静态方法没有参数,故可以不传东西
hello
>>> A.foo3()     #这里,由于是类方法,因此,它的第一个参数为类本身。
hello <class '__main__.A'>

>>> A         #可以看到,直接输入A,与上面那种调用返回同样的信息。
<class '__main__.A'>

3、whats more,类先调用__new__方法,返回该类的实例对象,这个实例对象就是__init__方法的第一个参数self,即self是__new__的返回值。

总结

到此这篇关于深入浅析python 中的self和cls的区别的文章就介绍到这了,更多相关python 中的self和cls内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
利用soaplib搭建webservice详细步骤和实例代码
Nov 20 Python
浅谈python中的变量默认是什么类型
Sep 11 Python
Python常用内置模块之xml模块(详解)
May 23 Python
python对list中的每个元素进行某种操作的方法
Jun 29 Python
OpenCV HSV颜色识别及HSV基本颜色分量范围
Mar 22 Python
简单了解python高阶函数map/reduce
Jun 28 Python
对Django项目中的ORM映射与模糊查询的使用详解
Jul 18 Python
python创建与遍历List二维列表的方法
Aug 16 Python
python飞机大战 pygame游戏创建快速入门详解
Dec 17 Python
TensorFlow实现checkpoint文件转换为pb文件
Feb 10 Python
sklearn和keras的数据切分与交叉验证的实例详解
Jun 19 Python
用python写PDF转换器的实现
Oct 29 Python
浅谈Python 参数与变量
Jun 20 #Python
python字符串的index和find的区别详解
Jun 20 #Python
Django Admin 上传文件到七牛云的示例代码
Jun 20 #Python
什么是python的函数体
Jun 19 #Python
浅谈Python中的生成器和迭代器
Jun 19 #Python
python中有帮助函数吗
Jun 19 #Python
python中导入 train_test_split提示错误的解决
Jun 19 #Python
You might like
php 全文搜索和替换的实现代码
2008/07/29 PHP
php代码审计比较有意思的例子
2014/05/07 PHP
Yii针对添加行的增删改查操作示例
2016/10/18 PHP
Thinkphp 中 distinct 的用法解析
2016/12/14 PHP
php探针不显示内存解决方法
2019/09/17 PHP
基于laravel-admin 后台 列表标签背景的使用方法
2019/10/03 PHP
Ext grid 添加右击菜单
2009/11/26 Javascript
js传参数受特殊字符影响错误的解决方法
2013/10/21 Javascript
Javascript操作URL函数修改版
2013/11/07 Javascript
Jquery 改变radio/checkbox选中状态,获取选中的值(示例代码)
2013/12/12 Javascript
JS实现的多张图片轮流播放幻灯片效果
2016/07/22 Javascript
jQuery Ajax Post 回调函数不执行问题的解决方法
2016/08/15 Javascript
jq实现左滑显示删除按钮,点击删除实现删除数据功能(推荐)
2016/08/23 Javascript
Vue.js父与子组件之间传参示例
2017/02/28 Javascript
jQuery使用eraser.js插件实现擦除、刮刮卡效果的方法【附eraser.js下载】
2017/04/28 jQuery
Ionic3 UI组件之autocomplete详解
2017/06/08 Javascript
详解在vue-cli项目中安装node-sass
2017/06/21 Javascript
使用travis-ci如何持续部署node.js应用详解
2017/07/30 Javascript
BootStrap Table实现server分页序号连续显示功能(当前页从上一页的结束序号开始)
2017/09/12 Javascript
jQuery轻量级表单模型验证插件
2018/10/15 jQuery
webpack中的模式(mode)使用详解
2020/02/20 Javascript
js实现购物车商品数量加减
2020/09/21 Javascript
Python 代码性能优化技巧分享
2012/08/07 Python
python爬虫正则表达式之处理换行符
2018/06/08 Python
使用Python的datetime库处理时间(RPA流程)
2019/11/24 Python
flask利用flask-wtf验证上传的文件的方法
2020/01/17 Python
基于python实现图片转字符画代码实例
2020/09/04 Python
pandas按照列的值排序(某一列或者多列)
2020/12/13 Python
美国值得信赖的婚恋交友网站:eHarmony
2018/10/04 全球购物
澳大利亚玩具剧场:Toy Playhouse
2019/03/03 全球购物
英国家电购物网站:Sonic Direct
2019/03/26 全球购物
积极向上的团队口号
2014/06/06 职场文书
党政领导班子四风问题对照检查材料思想汇报
2014/10/02 职场文书
2015年学校安全管理工作总结
2015/05/11 职场文书
检举信的写法
2019/04/10 职场文书
 Redis 串行生成顺序编码的方法实现
2022/04/03 Redis