网站建设教程app,抖音代运营策划案,网站主机租用多少钱,wordpress 后台介绍在介绍Python的self用法之前#xff0c;先来介绍下Python中的类和实例…… 我们知道#xff0c;面向对象最重要的概念就是类#xff08;class#xff09;和实例#xff08;instance#xff09;#xff0c;类是抽象的模板#xff0c;比如学生这个抽象的事物#xff0c;…在介绍Python的self用法之前先来介绍下Python中的类和实例…… 我们知道面向对象最重要的概念就是类class和实例instance类是抽象的模板比如学生这个抽象的事物可以用一个Student类来表示。而实例是根据类创建出来的一个个具体的“对象”每一个对象都从类中继承有相同的方法但各自的数据可能不同。 1、以Student类为例在Python中定义类如下
class Student(object):pass
12
Object表示该类从哪个类继承下来的Object类是所有类都会继承的类。
2、实例定义好了类就可以通过Student类创建出Student的实例创建实例是通过类名()实现
student Student() #创建一个实例
1
3、由于类起到模板的作用因此可以在创建实例的时候把我们认为必须绑定的属性强制填写进去。这里就用到Python当中的一个内置方法__init__方法例如在Student类时把name、score等属性绑上去:
class Student(object):def __init__(self, name, score):self.name nameself.score score
1234
这里注意
1、__init__方法的第一参数永远是self表示创建的类实例本身因此在__init__方法内部就可以把各种属性绑定到self因为self就指向创建的实例本身。
2、有了__init__方法在创建实例的时候就不能传入空的参数了必须传入与__init__方法匹配的参数但self不需要传Python解释器会自己把实例变量传进去
student Student(Hugh, 99)
student.name
Hugh
student.score
99
12345
另外这里self就是指类本身self.name就是Student类的属性变量是Student类所有。而name是外部传来的参数不是Student类所自带的。故self.name name的意思就是把外部传来的参数name的值赋值给Student类自己的属性变量self.name。
4、和普通数相比在类中定义函数只有一点不同就是第一参数永远是类的本身实例变量self并且调用时不用传递该参数。除此之外类的方法(函数和普通函数没啥区别你既可以用默认参数、可变参数或者关键字参数*args是可变参数args接收的是一个tuple**kw是关键字参数kw接收的是一个dict。
5、既然Student类实例本身就拥有这些数据那么要访问这些数据就没必要从外面的函数去访问而可以直接在Student类的内部定义访问数据的函数方法这样就可以把”数据”封装起来。这些封装数据的函数是和Student类本身是关联起来的称之为类的方法
class Student(obiect):def __init__(self, name, score):self.name nameself.score scoredef print_score(self):print %s: %s % (self.name, self.score)
123456
student Student(Hugh, 99)
student.print_score
Hugh: 99
123
这样一来我们从外部看Student类就只需要知道创建实例需要给出name和score。而如何打印都是在Student类的内部定义的这些数据和逻辑被封装起来了调用很容易但却不知道内部实现的细节。
如果要让内部属性不被外部访问可以把属性的名称前加上两个下划线在Python中实例的变量名如果以开头就变成了一个私有变量private只有内部可以访问外部不能访问所以我们把Student类改一改
class Student(object):def __init__(self, name, score):self.__name nameself.__score scoredef print_score(self):print %s: %s %(self.__name,self.__score)
1234567
改完后对于外部代码来说没什么变动但是已经无法从外部访问实例变量.__name和实例变量.__score了student Student(Hugh, 99)student.__name
Traceback (most recent call last):File stdin, line 1, in module
AttributeError: Student object has no attribute __name
12345
这样就确保了外部代码不能随意修改对象内部的状态这样通过访问限制的保护代码更加健壮。
但是如果外部代码要获取name和score怎么办可以给Student类增加get_name和get_score这样的方法
class Student(object):...def get_name(self):return self.__namedef get_score(self):return self.__score
12345678
如果又要允许外部代码修改score怎么办可以给Student类增加set_score方法
class Student(object):...def set_score(self, score):self.__score score
12345
需要注意的是在Python中变量名类似__xxx__的也就是以双下划线开头并且以双下划线结尾的是特殊变量特殊变量是可以直接访问的不是private变量所以不能用__name__、__score__这样的变量名。
有些时候你会看到以一个下划线开头的实例变量名比如_name这样的实例变量外部是可以访问的但是按照约定俗成的规定当你看到这样的变量时意思就是“虽然我可以被访问但是请把我视为私有变量不要随意访问”。
封装的另一个好处是可以随时给Student类增加新的方法比如get_grade:
class Student(object):...def get_grade(self):if self.score 90:return Aelif self.score 60:return Belse:return C
123456789
同样的get_grade方法可以直接在实例变量上调用不需要知道内部实现细节student.get_grade()
A
12
6、self的仔细用法 (1)、self代表类的实例而非类。
class Test:def ppr(self):print(self)print(self.__class__)t Test()
t.ppr()
执行结果
__main__.Test object at 0x000000000284E080
class __main__.Test
12345678910
从上面的例子中可以很明显的看出self代表的是类的实例。而self.__class__则指向类。 注意把self换成this结果也一样但Python中最好用约定俗成的self。 2、self可以不写吗 在Python解释器的内部当我们调用t.ppr()时实际上Python解释成Test.ppr(t)也就是把self替换成了类的实例。
class Test:def ppr():print(self)t Test()
t.ppr()
123456
运行结果如下
Traceback (most recent call last):File cl.py, line 6, in modulet.ppr()
TypeError: ppr() takes 0 positional arguments but 1 was given
1234
运行时提醒错误如下ppr在定义时没有参数但是我们运行时强行传了一个参数。
由于上面解释过了t.ppr()等同于Test.ppr(t)所以程序提醒我们多传了一个参数t。
这里实际上已经部分说明了self在定义时不可以省略。
当然如果我们的定义和调用时均不传类实例是可以的这就是类方法。
class Test:def ppr():print(__class__)Test.ppr()运行结果
class __main__.Test
12345678
3、在继承时传入的是哪个实例就是那个传入的实例而不是指定义了self的类的实例。
class Parent:def pprt(self):print(self)class Child(Parent):def cprt(self):print(self)
c Child()
c.cprt()
c.pprt()
p Parent()
p.pprt()
123456789101112
运行结果
__main__.Child object at 0x0000000002A47080
__main__.Child object at 0x0000000002A47080
__main__.Parent object at 0x0000000002A47240
123
解释 运行c.cprt()时应该没有理解问题指的是Child类的实例。 但是在运行c.pprt()时等同于Child.pprt(c)所以self指的依然是Child类的实例由于self中没有定义pprt()方法所以沿着继承树往上找发现在父类Parent中定义了pprt()方法所以就会成功调用。
4、在描述符类中self指的是描述符类的实例
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()
t.x
1234567891011
运行结果如下
self in Test: __main__.Test object at 0x0000000002A570B8
self in Desc: __main__.Desc object at 0x000000000283E208
__main__.Desc object at 0x000000000283E208 __main__.Test object at 0x0000000002A570B8 class __main__.Test
123
这里主要的疑问应该在Desc类中定义的self不是应该是调用它的实例t吗怎么变成了Desc类的实例了呢 因为这里调用的是t.x也就是说是Test类的实例t的属性x由于实例t中并没有定义属性x所以找到了类属性x而该属性是描述符属性为Desc类的实例而已所以此处并没有顶用Test的任何方法。
那么我们如果直接通过类来调用属性x也可以得到相同的结果。
下面是把t.x改为Test.x运行的结果。self in Test: __main__.Test object at 0x00000000022570B8
self in Desc: __main__.Desc object at 0x000000000223E208
__main__.Desc object at 0x000000000223E208 None class __main__.Test
---------------------------------------------------------------------------------------------------------self可以理解为自己类似于C中的this指针就是对象自身的意思在用某个对象调用该方法时就将该对象作为第一个参数传递给self
python的类中有属性、方法其中属性可以有私有和公有之分方法可以对私有属性进行限定和保护类似于C#中属性的功能。
方法也有私有和公有__方法前面两个下划线
类具有相似内部状态和运动规律的实体的集合统称、抽象具有相同属性和行为事物的统称类是抽象的使用时找到类的具体存在使用这个具体存在--对象类是对象的模板 类类名、属性、方法[python] view plaincopyclass Dog: colorred #没有下划线类外可以通过对象访问公有 age10 __height10 #私有属性这个地方前面加了下划线代表不可以在外面使用 def setName(self,newName): self.namenewName self.__weight20 def printheight(self): print(the height is %d%self.__height) print(the weight is %d%self.__weight) dogDog() dog.setName(Bule) #调用这个方法后才可以访问私有__weight print(dog.color) dog.printheight() #属性用来保存数据私有属性体现了封装性 #方法中的self必须为第一个参数用来接收对象使用 self的作用可以在方法中将对象替换掉self
[python] view plaincopyclass Person( ): #构造方法在创建对象的同时默认调用 def __init__(self): self.countryChinese def __del__(self): print(析构方法)#当删除一个对象时默认调用析构方法 __nameLily __age12 docstring for ClassName def __getName(self):#在这个方法中可以对属性进行一些限定类似于C#中的属性功能 return self.__name def __getAge(self):#对属性进行限定和保护 if self.__age18: return self.__age else: return 18 def getNameAge(self): name1self.__getName() age1self.__getAge() print(name is %s,age is %d%(name1,age1)) personPerson() person.getNameAge() #print(p.getAge(),p.getName())#两个方法是私有的不可以在类外面调用 del person #调用析构方法 方法可以返回元组def test: return100,200,200 a,b,ctest()[python] view plaincopyclass Teacher: age30 def __init__(self): print(父类的构造方法) def showName(self,name): self.namename print(Name is %s%self.name) def showAge(self,age): self.ageage print(Age is %d%self.age) class Student(Teacher ): #pass#子类继承父类父类的东西子类都包含只写pass def __init__(self): Teacher.__init__(self) #根据这两行的先后顺序决定先执行父类还是子类方法 print(子类重写父类的方法 子类的构造方法) def Special(self): print(Student is a child) class Doctor(): pass #class pel(Teacher,Student):#多继承,有错误Cannot create a consistent method resolution继承太多 # pass class pe2(Teacher,Doctor): pass teacherTeacher() studentStudent() teacher.showAge(30) teacher.showName(Mr li) #子类的方法名与父类的方法名相同重写。子类的对象会调用子类的 #多态的概念应用于Java和C#这一类强类型语言中而Python崇尚‘鸭子类型’ 123