python自学笔记9 —— 面向对象编程
9.0 基本知识
9.0.1 几个常见名词
- 类 : 学生
- 对象 : 大明 萨姆 李红
- 属性 : 身高 体重 爱好
- 方法 : 学习 睡觉 吃饭
其中,所有类要求首字母大写,多个单词组合要求驼峰式命名:
例如:Students StudentsClass1 Books MyBooks
9.0.2 常见格式
class 类名(父类) :
#属性
#方法
9.1 属性
9.1.0 简单的创建与调用
# 定义一个类,类中有类属性
class Student:
name = 'Daming'
# 这里的name就是类属性
# 创建一个对象
a = Student() # a就是Student类里的一个对象
# 调用类属性
print(a.name)
# 输出结果为:
# Daming
9.1.1 修改属性
修改对象属性
class Student:
age = 18
# 这里的name就是类属性
Daming = Student()
Daming.age = 25
print("Daming's age = ",Daming.age)
Liwei = Student()
print("Liwei's age = ",Liwei.age)
# 输出结果为:
# Daming's age = 25
# Liwei's age = 18
这里可以观察到,修改了Student类的Daming对象的age属性,并不能使Student类的age属性发生改变。
此时修改的是对象属性,类属性不变,但是可以通过以下方法修改类属性。
# 还是上面那个Student类
class Student:
age = 18
Student.age = 25
Ammy = Student()
print("Ammy's age = ",Ammy.age)
# 输出结果为:
# Ammy's age = 25
此时Student类的age属性已经发生改变
9.2 方法
- 方法的定义与之前定义函数一样
- 方法中的第一个输入参数必须为self
9.2.0 简单的创建与调用
# 一个简单的面向对象方法代码
class Classmates():
def func1(self):
print("我爱python")
def func2(self):
print("python也爱我")
student1 = Classmates()
student1.func1()
student1.func2()
# 输出结果为:
# 我爱python
# python也爱我
9.3 魔术方法
什么是魔术方法?
- 形式例如 init(self)
- 已经由python库写好,用户不能随意更改
魔术方法1 init(self)
当创建一个对象时,都会执行一遍类的__init__(self)函数,作用类似于初始化.
class Class():
def __init__(self):
print("正在执行inti函数")
print("打印self",self)
class1 = Class()
print("打印class1",class1)
# 输出结果为:
# 正在执行inti函数
# 打印self <__main__.Class object at 0x000002B58DA47EB0>
# 打印class1 <__main__.Class object at 0x000002B58DA47EB0>
从输出结果来看:
- 该程序中,我们并没有调用class1中的__init__(self),只是打印了class1,这印证了 : 当创建一个对象时,都会执行一遍类的__init__(self)函数,作用类似于初始化.
- 通过打印,我们发现,self就是class1.也就是说,self的实质就是生成的对象.
改写 init(self) —> 函数在创建对象的同时就可以设置对象的属性
class Students:
def __init__(self,name,age):
self.name = name
self.age = age
def printer(self):
print("学生姓名为 {0},学生年龄为 {1}".format(self.name,self.age))
student = Students("Tom",11)
student.printer()
# 输出结果为:
# 学生姓名为 Tom,学生年龄为 11
魔术方法2 del(self)
当调用del语句删除对象时,就会执行类的这个函数,我们也可以改写这个函数
class Students:
def __del__(self):
print("我们删掉了这个对象!")
student = Students()
del student
# 输出结果为:
# 我们删掉了这个对象!
魔术方法3 str(self)
当使用print函数打印对象时,就会执行类的这个函数,我们也可以改写这个函数
class Students:
def __str__(self):
return "我们改写了这个方法"
s = Students();
print(s)
# 输出结果为:
# 我们改写了这个方法
我们可以用改写__str__(self)来输出对象的所有属性.
魔术方法4 repl(self)
与魔术方法3 str(self)相似,只不过是顺序问题.例如,在打印对象时,若__str__(self)没有被改写,便会来看__repl__(self)的内容.若两者都没有被改写,则会直接打印对象的地址
魔术方法5 call(self)
直接在对象名后加 () 便可以触发
class Students:
def __call__(self):
print("我们改写了这个方法")
s = Students();
s()
# 输出结果为:
# 我们改写了这个方法
9.4 内置属性
内置属性1 slots
限制对象不能添加动态属性
class Students:
__slots__ = ('name','age')
def __init__(self,name,age):
self.name = name
self.age = age
s1 = Students("Tom","17")
s1.weight = 120
#输出报错
内置属性2 doc
输出类的描述信息
class Students:
"""这里就是输出"""
def func(self):
pass
print(Students.__doc__)
#这里就是输出
9.5 私有属性和私有方法
9.5.0 简单的创建
在定义属性或方法时,在属性名或者方法名前增加两个下划线__,定义的就是私有属性或方法。
此时不能通过普通的调用方式来调用私有属性或方法
class Students():
__name = "abc"
def __printer(self):
print("abc")
s1 = Students()
print(s1.__name)
s1.__printer
# 发生报错
9.5.1 访问私有属性和私有方法
法1. 直接访问. 通过在私有属性和私有方法前加_类名,便可以直接访问
class Students():
__name = "abc"
def __printer(self):
print("abcd")
s2 = Students()
print(s2._Students__name)
s2._Students__printer()
# 输出结果为 :
# abc
# abcd
法2. 定义方法访问私有变量
class Students():
__name = "abc"
def __printer(self):
print("abcd")
def get_name(self): # 使用get_name输出__name
return self.__name
def set_name(self, newname): # 使用set_name修改__name
self.__name = newname
def get_printer(self): # 使用get_printer输出__printer
self.__printer()
s1 = Students()
# 测试输出__printer
s1.get_printer()
# 输出成功 : abcd
# 测试输出__name
name1 = s1.get_name()
print(name1)
# 输出成功 : abc
# 测试修改并输出__name
s1.set_name('hhh')
name2 = s1.get_name()
print(name2)
# 输出成功 : hhh
9.6 类方法
需要用 @classmethod 来装饰,且第一个参数必须为cls(类),其他参数必须为类参数(可以是私有参数)
class Students():
__name = "abc"
@classmethod
def printer(cls):
print(Students.__name)
Students.printer() # 通过类来调用类方法
d = Students()
d.printer() # 通过对象来调用类方法
# 输出结果为 :
# abc
# abc
9.7 静态方法
需要用 @staticmethod 来装饰,不需要类参数(cls)或者对象参数(self)
class Students():
@staticmethod
def printer():
print("这是一个静态方法!")
Students.printer() # 通过类来调用类方法
s = Students()
s.printer() # 通过对象来调用类方法
# 输出结果为 :
# 这是一个静态方法!
# 这是一个静态方法!
9.8 new与init
__new__方法输出实例化对象
__init__方法的输入为实例化对象
即 先有 new 再有 init
9.9 继承
面向对象的三个基本特征 : 继承 多态 封装
9.9.1 单继承
class School(object): # object是python的基类,即所有类都是object的对象,故 万物皆对象
school_name = "DK8"
def printer(self):
print("Dalian K8 welcome to you!")
class Three1(School): # Three1是School的一个子类,可以调用School中的方法和属性
pass
t = Three1()
t.printer()
print(t.school_name)
# 输出结果为 :
# Dalian K8 welcome to you!
# DK8
9.9.2 继承的传递性
class School(object): # object是python的基类,即所有类都是object的对象,故 万物皆对象
school_name = "DK8"
def printer(self):
print("Dalian K8 welcome to you!")
class Three1(School): # Three1是School的一个子类,可以调用School中的方法和属性
pass
class Student(Three1): # Student是Three1的一个子类,可以调用Three1中的方法和属性
pass
s = Student()
s.printer()
print(s.school_name)
# 输出结果为 :
# Dalian K8 welcome to you!
# DK8
这里我们可以看到,Student是Three1的子类,而Three1又是School的子类,但是Student可以直接调用School中的方法和属性,故继承具有传递性。
9.9.3 多重继承
class Class1():
def printer1(self):
print("here is class1")
class Class2():
def printer2(self):
print("here is Class2")
class Student(Class1,Class2):
pass
s = Student()
s.printer1()
s.printer2()
# 输出结果为 :
# here is class1
# here is Class2
重继承中,应该避免多个父类中含有函数名一样的方法。
当这种情况存在时,将以最后一个父类的函数为准。
9.10 多态
当多个对象需要执行一类动作时,有以下两种方式
法一
class Class(object):
def write1(self,student):
student.writer1()
def write2(self, student):
student.writer2()
class Student1(object):
def writer1(self):
print("Student1 is here")
class Student2(object):
def writer2(self):
print("Student2 is here")
class1 = Class()
s1 = Student1()
s2 = Student2()
class1.write1(s1)
class1.write2(s2)
# 输出结果为 :
# Student1 is here
# Student2 is here
这样代码并没有问题
但是当我们的学生(Student)多了起来时,他们每个人的方法都不一样
我们需要在Class类里加代码
这样做拓展性太低
于是有了面向对象的多态性(利用了继承)
即法二
class Student(object):
def writer(self): # 父类提供统一方法,即使是空函数
pass
class Student1(Student):
def writer(self): # 子类重写父类方法
print("Student1 is here")
class Student2(Student):
def writer(self): # 子类重写父类方法
print("Student2 is here")
class Student3(Student):
def writer(self): # 子类重写父类方法
print("Student3 is here")
s1 = Student1()
s2 = Student2()
s3 = Student3()
s1.writer()
s2.writer()
s3.writer()
# 输出结果为 :
# Student1 is here
# Student2 is here
# Student3 is here
9.11 对象的内置函数
9.11.1 身份运算符 is
用于判断两个对象是否为同一个对象
class Student():
def __init__(self,name):
self.name = name
pass
def printer(self):
print(self.name)
s1 = Student("abc")
s2 = Student("abc")
s3 = s1
print(s1 is s2)
print(s1 is s3)
# 输出结果为 :
# False
# True
可以看出,比较的依据并不是对象的内容,而是对象所在的地址。
9.11.2 isinstance
用于判断一个对象是否是由某一个类(或者它的子类)创建出来的。
class Student():
def __init__(self,name):
self.name = name
pass
def printer(self):
print(self.name)
class School():
def __init__(self, name):
self.name = name
pass
def printer(self):
print(self.name)
s1 = Student("abc")
print(isinstance(s1,Student))
print(isinstance(s1,School))
# 输出结果为 :
# True
# False
9.11.3 issubclass
用于判断一个类是否为另一个类的子类。
class School(object):
def __init__(self, name):
self.name = name
pass
def printer0(self):
print(self.name)
class Student(School):
pass
print(issubclass(Student,School))
print(isinstance(School,Student))
# 输出结果为 :
# True
# False