【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