【python学习笔记】python中的self理解

本篇博客参考:
Python中self用法详解
Python - 静态函数(staticmethod), 类函数(classmethod), 成员函数 区别(完全解析)

self指的就是类实例对象本身

使用场景如下

__init__

__init__ 方法的第一参数永远是self,表示创建的类实例本身

有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器会自己把实例变量传进去

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
student = Student("Hugh", 99)
print(student.name)
print(student.score)
Hugh
99

成员函数

数据封装

name和score是student的内部变量,用的时候就可以使用函数将其封装

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def Printinfo(self):
        print(self.name + ':' + str(self.score))

ryu = Student('ryu',98)
ryu.Printinfo()
ryu:98

但是此时,外部可以更改ryu的name和score

ryu.name = 'tyo'
ryu.Printinfo()
tyo:98

把name和score设置成私有变量可以避免这一问题,此时不能通过对象名.变量名来获得具体值,有需要的话可以通过添加get set函数获取。

class Student(object):
    def __init__(self, name, score):
        self.__name = name #私有变量
        self.__score = score #私有变量
        
    def printInfo(self):
        print(self.__name + ':' + str(self.__score))
        
    def getName(self):
        print(self.__name)
        
    def getScore(self):
        print(self.__score)
        
    def setName(self, name):
        self.__name = name
        
    def setScore(self, score):
        self.__score = score
        
ryu = Student('ryu',98)
ryu.printInfo()

#print(ryu.__name) 这条会报错

ryu.name = 'tyo'
ryu.printInfo()
ryu:98
ryu:98
ryu.getName()
ryu.getScore()
ryu.setName('tyo')
ryu.setScore(100)
ryu.printInfo()
tyo
100
tyo:100

继承时

在继承时,传入的是哪个实例,就是那个传入的实例,而不是指定义了self的类的实例。

class Parent:
    def pprt(self):
        print(self)

class Child(Parent):
    def cprt(self):
        print(self)

c = Child()
c.cprt()
#等同于Child.pprt(c),所以self指的依然是Child类的实例
#由于self中没有定义pprt()方法,所以沿着继承树往上找,发现在父类Parent中定义了pprt()方法,所以就会成功调用。
c.pprt()
p = Parent()
p.pprt()
<__main__.Child object at 0x000001EF6BBB2188>
<__main__.Child object at 0x000001EF6BBB2188>
<__main__.Parent object at 0x000001EF6BBB2F08>

描述符类中

self指的是描述符类的实例

class Desc:
    
    #ins,用来表示调用它的类实例,若没有实例调用则为None
    def __get__(self, ins, cls):
        print('self in Desc: %s ' % self )
        print(self, ins, cls)
class Test:
    x = Desc()
    def prt(self):
        print('self in Test: %s' % self)
t = Test()
t.prt()
t.x
self in Test: <__main__.Test object at 0x0000025C9C4C5388>
self in Desc: <__main__.Desc object at 0x0000025C9C4C5308> 
<__main__.Desc object at 0x0000025C9C4C5308> <__main__.Test object at 0x0000025C9C4C5388> <class '__main__.Test'>

这里主要的疑问应该在:Desc类中定义的self不是应该是调用它的实例t吗?怎么变成了Desc类的实例了呢?
因为这里调用的是t.x,也就是说是Test类的实例t的属性x,由于实例t中并没有定义属性x,所以找到了类属性x,而该属性是描述符属性,为Desc类的实例而已,所以此处并没有顶用Test的任何方法。

那么我们如果直接通过类来调用属性x也可以得到相同的结果。

下面是把t.x改为Test.x运行的结果。

class Desc:
    def __get__(self, ins, cls):
        print('self in Desc: %s ' % self )
        print(self, ins, cls)
class Test:
    x = Desc()
    def prt(self):
        print('self in Test: %s' % self)
t = Test()
t.prt()
Test.x
self in Test: <__main__.Test object at 0x000001EF6BF34408>
self in Desc: <__main__.Desc object at 0x000001EF6B8FCF88> 
<__main__.Desc object at 0x000001EF6B8FCF88> None <class '__main__.Test'>

不使用self的情况

  • 类函数:更关注于从类中调用方法, 而不是在实例中调用方法, 如构造重载,可以进行数据转换。方法的第一个参数是class对象
  • 静态函数:主要处理与这个类的逻辑关联, 如验证数据。第一个参数不需要是class对象或者实例self。
class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
        
    def Printinfo(self):
        print(self.name + ':' + str(self.score))
    
    @classmethod
    def classFunction(cls, info):
        name, score = info.split(' ')
        stu = cls(name, score)
        return stu
    
    @staticmethod
    def ifgood(score):
        return score>=90

ryu = Student('ryu',98)
ryu.Printinfo()
#ryu.classFunction() 会报错classFunction() takes 0 positional arguments but 1 was given
li = Student.classFunction('li 89')
li.Printinfo()
li.ifgood(int(li.score))
Student.ifgood(99)
ryu:98
li:89

True
posted @ 2021-03-08 12:29  ryukirin  阅读(403)  评论(0编辑  收藏  举报