面向对象概念 和java一样,类(class)和对象是面向对象的体现,它是一种设计思想现实生活在计算机世界的映射。类的最基本作用就是封装代码,在一个类里可以定义很多个类。
1,类的定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Student(): #可以在类体定义变量 name = '' age = 0 c = 9 #也可以在类体定义函数 def print_file(self): #要加self def print_file(self): print('name:' + name) print('name:' + str(age) #然而运行还是会报错 PS G:\python> python test10.py Traceback (most recent call last): File "test10.py", line 15, in <module> student.print_file() File "test10.py", line 11, in print_file print('name:' + name) NameError: name 'name' is not defined #显示没有定义 name变量 #正确的方法是在name和age这两个变量前加self.来引用。 class Student(): name = '' age = 0 def print_file(self): print('name:' + self.name) print('name:' + str(self.age)) student = Student() student.print_file() #运行结果 PS G:\python> python test10.py name: name:0
1.1 方法与函数的区别 1,实际上很多时候我们都把他们划等号,java、c#一般称为方法,c和c++一般称函数。 2,方法:趋向于面向对象的概念,python建议称方法,在模块里就建议称函数。 3,函数:面向过程的概念当然没有必要刻意强调它们的区别
1.2 变量 1,在模块中定义的就称变量 2,在类中定义的就称为数据成员(这样以体现封装性)。
1.3 类和对象的关系和区别 类的定义:类是现实世界或思维世界中的实体在计算机中的反映,它将数据以及这些数据上的操作封装在一起。 类只是一类事物的总称,并不是一个具体的集合,具体的对象表示具体的类的一个实例,类的实例化就生成一个对象。
1.4 类的实例化 1 2 3 4 5 6 7 8 9 10 11 student1 = Student() student2 = Student() student3 = Student() print(id(student1)) print(id(student2)) print(id(student3)) #运行结果,可以看到他们的内存地址都是不同的 PS G:\python> python test10.py 2479712232448 2479712232840 2479712232616
构造函数只能返回none,不能返回其他类型的值,比如字符串。 我们在实例化对象的时候要在构造函数传入定义的变量,然后赋值,在生成对象的时候传入我们要定义的实际参数的值,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Student(): name = '' age = 0 def __init__(self,name,age): #这是构造函数 name = name age = age def print_file(self): print('name:' + self.name) print('name:' + str(self.age)) student1 = Student('石头',18) print(student1.name) #打印 PS G:\python> python test10.py #但是输出却是空,为什么?再看一个小例子: c = 50 def add(x,y): c = x + y print(c) add(1,2) print(c) #输出结果 PS G:\python> python test11.py 3 50
这里我们在函数内部打印c的值是3,在外部打印c的值是50,在函数里面c是局部变量,不会改变全局变量的值,不过类的情况不同。下面分析一下。
1.5 类变量和实例变量 类变量时和类相关联的,实例变量是和对象相关联的,python里面是用self.变量名来保存实例变量的值。如下代码所示,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class Student(): name = '' age = 0 def __init__(self,name,age): #这是构造函数 self.name = name self.age = age def print_file(self): print('name:' + self.name) print('name:' + str(self.age)) student1 = Student('石头',18) # student1 = Student('石敢',18) print(student1.name,student1.age) #运行结果 PS G:\python> python test10.py 石头 18 #再看如下代码 class Student(): #不适合定义在这里 name = 'qiyue' age = 0 def __init__(self,name,age): #这是构造函数 self.name = name self.age = age def print_file(self): print('name:' + self.name) print('name:' + str(self.age)) student1 = Student('石头',18) student2 = Student('石敢',18) print(student1.name) print(student2.name) print(Student.name) #运行结果 PS G:\python> python test10.py 石头 石敢 qiyue 两个对象的name是不同的,所以打印出不同的结果,最后一行打印出qiyue,这是类变量,但是这样没有意义,名字和年龄应该定义成实例变量,而不是定义在如上代码的位置,因为类不是具体的一个对象。
下面分析一下类变量和实例变量的有关问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Student(): name = 'qiyue' age = 0 def __init__(self,name,age): name = name age = age student1 = Student('石头',18) print(student1.name) #打印 PS G:\python> python test10.py qiyue qiyue
如上代码所示,我们打印对象student1的name是qiyue,直接打印类的变量name值也是qiyue,后者好理解,可是我们为什么试图打印student1的name也是qiyue而不是石头呢?
1 2 3 def __init__(self,name,age): name = name age = age
我们这样写是不会给对象赋值的,应该配合self来使用。
1 2 3 def __init__(self,name,age): self.name = name self.age = age
self 如果定义的是实例方法,那我们必须在方法的参数列表第一个固定加上self,这是python的规定(实际上也可以用this,不过建议self),要显式的传入self,self就代表当前对象,不过我们调用实例方法的时候不需要传self,代码:
1 2 3 4 5 6 7 8 9 10 11 #定义的时候要在参数列表第一个位置加self class Student(): name = 'qiyue' age = 0 def __init__(self,name,age): self.name = name self.age = age #调用的时候则不需要这么做 student1 = Student('石头',18)
如果要在实例方法中和函数外访问类变量,应该用类名.变量名调用。方法一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Student(): sum1 = 0 name = 'qiyue' age = 0 def __init__(self,name,age): self.name = name self.age = age print(Student.sum1) student1 = Student('石头',18) print(student1.name) print(Student.sum1) class Student(): sum1 = 0 name = 'qiyue' age = 0 def __init__(self,name,age): self.name = name self.age = age print(Student.sum1) student1 = Student('石头',18) print(student1.name) print(Student.sum1) #运行结果 PS G:\python> python test10.py 0 石头 0
方法二:通过self,self有一个自带的class,它就是Student类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Student(): sum1 = 0 name = 'qiyue' age = 0 def __init__(self,name,age): self.name = name self.age = age print(self.__class__.sum1) student1 = Student('石头',18) print(student1.name) print(Student.sum1) #打印结果 PS G:\python> python test10.py 0 石头 0
2,类方法 为什么会有类方法?它有什么作用?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Student(): sum = 0 # name = 'qiyue' # age = 0 def __init__(self, name, age): self.name = name self.age = age self.__class__.sum += 1 print('当前班级学生总数为:' + str(self.__class__.sum)) def do_homework(self): print('do homework') student1=Student('小明', 18) student1=Student('小强', 18) student1=Student('小黄', 18) #运行结果 PS G:\python> python test10.py 当前班级学生总数为:1 当前班级学生总数为:2 当前班级学生总数为:3
类变量也有一个专门操作它的方法,叫类方法
1 2 3 @classmethod def plus_sum(cls): pass
这是类方法定义的规范,在方法前面添加一个装饰器@classmethod。类方法怎么调用呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Student(): sum = 0 # name = 'qiyue' # age = 0 def __init__(self, name, age): self.name = name self.age = age self.__class__.sum += 1 print('当前班级学生总数为:' + str(self.__class__.sum)) @classmethod def plus_sum(cls): cls.sum += 1 print(cls.sum) student1=Student('小明', 18) Student.plus_sum() student1=Student('小强', 18) Student.plus_sum() student1=Student('小黄', 18) Student.plus_sum() #打印 PS G:\python> python test10.py 当前班级学生总数为:1 2 当前班级学生总数为:3 4 当前班级学生总数为:5 6
实例化对象的时候,对sum操作 加1,然后在类方法中又对sum进行加1操作,所以会如上代码打印。cls可以 叫别的名字吗?可以,我们换成self也同样可以。实例方法关联的是对象,类方法关联的是类。这是区别,既然可以在实例方法中操作类变量,那还要类方法做什么?因为在操作与对象无关的变量,最正确的方法还是用类方法(实例方法也可以,但是不建议)。self和cls self是可以代表当前对象的一个参数;cls是代表当前类的一个参数,代表当前类。 也可以用对象调用类的方法(不建议,java中就不可以这么做)。
3,静态方法 定义:
1 2 3 @staticmethod def add(x,y): print('This is a static method')
调用:
1 2 3 4 5 6 7 8 9 ... student1=Student('小明', 18) student1.add(1,2) Student.add(1,2) ... #运行结果 PS G:\python> python test10.py This is a static method This is a static method
注:省略了部分代码。静态方法可以用类和对象调用。静态方法也可以访问类变量。静态方法不建议经常用。
4,成员的可见性 面向对象语言都有这个概念,java使用private、public来修饰,也叫权限修饰符。python是怎么定义一个方法的权限呢?:双下划线。 在方法前面加双下划线。如:
1 2 3 4 5 def __marking(self,score): if score < 0: return '分数不合法,请重新打分' self.score = score print(self.name + '同学本次考试分数为:' + str(self.score))
这里有个疑问,构造函数也是前面有双下划线为什么不是私有的?仔细看,init后面还有双下划线,在python里,函数名前后都有双下划线就不会被认为是私有函数,我们可以运行函数来证明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ... def marking(self,score): if score < 0: return '分数不合法,请重新打分' self.score = score print(self.name + '同学本次考试分数为:' + str(self.score)) ... student1=Student('小明', 18) result = student1.marking(-9) print(result) #运行结果 PS G:\python> python test10.py 分数不合法,请重新打分 #这里运行了marking方法,我们在前面加双下划线,运行结果如下: PS G:\python> python test10.py Traceback (most recent call last): File "test10.py", line 50, in <module> result = student1.marking(-9) AttributeError: 'Student' object has no attribute 'marking' #果然,现在不能访问了,"no attribute 'marking'",我们再在marking后面加双下划线 "__marking__",则可以调用。当然这样不建议,因为它是python内置的定义方式。
我们可以强制访问,在调用的时候在变量前面加双下划线。如: student1.__score = 1.
1 2 3 4 5 6 7 8 9 student1=Student('小明', 18) result = student1.marking(9) student1.__score = -9 print(student1.__score) #打印 PS G:\python> python test12.py 小明同学本次考试分数为:59 -1 {'name': '小明', 'age': 18, '_Student__score': 59, '__score': -1}
注意 _Student__score ,它就是我们定义的私有变量score,这是python私有变量的保护机制。为什么我们访问不到这个 score变量,实际上就是python修改了它的名字,前面加上单下划线和类名。严格意义上python并没有私有变量。我们还是可以访问所谓的私有变量,”students._Student__score”。
1 2 3 4 5 6 7 8 9 10 11 student1=Student('小明', 18) student2=Student('小兰', 18) result = student1.marking(59) student1.__score = -1 print(student1.__score) print(students._Student__score) #打印 PS G:\python> python test12.py 小明同学本次考试分数为:59 -1 0