前言:
python是一种面向对象的语言。面向对象的语言都有类这种数据结构,类有3大特点:继承、封装、多态。
对这些概念不必过多深究,会用了自然知道什么意思。
1- 初始 类、对象
语法:
#类的语法
class 类名(父类):
xxx
#对象语法
对象名 = 类名(入参)
可以把类理解成C语言中的结构体,把对象理解为结构体变量。
示例:
下面建立了一个类People,继承的父类为object。
创建了个Mic的方法。
【知识点】
__init__:在创建对象时执行
实例方法:类中的一般方法,比如def age、def weight等
私有方法:以__开头的方法,如def __private_func。该函数只能由类内的方法访问。类似于C语言中加了static关键字
类变量:类中方法外边的变量。比如cnt,类变量只能由类名.类变量的方式访问
实例变量:类里面方法中的变量。
私有变量:以__开头的变量。该类型变量只能在类内访问,同私有方法。类似于在变量前加了static关键字
在创建Mic对象时,执行类的__init__接口,就是对象的初始化。
import os
class People(object):
cnt = 0
def __init__(self, name, age, weight):
self.name = name
self.__age = age
self.__weight=weight
print("{0} init, self.name:{1}".format(self.__class__, self.name))#self.__class__指向类
#私有变量访问
def age(self):
print("self.__age:{0}".format(self.__age))
def weitht(self):
print("self.__weight:{0}".format(self.__weight))
#访问私有函数
def __private_func(self):
print("private func: I have a secret...")
def call_private_func(self):
self.__private_func()
Mic = People("kk", 17, 145)
print("cnt:{0}".format(Mic.cnt))
print("name:{0}".format(Mic.name))
#访问私有变量
Mic.age()
Mic.weitht()
#访问私有方法
Mic.call_private_func()
2- 类方法、静态类方法
和1-定义的方法有所不同,1-定义的实例方法必须创建一个对象后,使用对象名.方法名引用,和对象强相关,且方法的定义格式为def func(self, arg)。
类方法不必创建对象,使用类名.类方法名即可引用,由于没有创建对象,所以没有了初始化。格式:必须有@classmethod修饰,def func(cls, arg)。
静态方法和类方法很像,使用类名.静态方法名即可引用。格式:必须有@staticmethod修饰,def func(arg)。这里连cls都省略了。
class 类名(object):
def __init__(self):
pass
@classmethod
def 类方法名(cls, arg):
pass
@staticmethod
def 静态方法名(arg):
pass
#引用
类名.类方法名(arg)
类名.静态方法名(arg)
综上:
实例方法引用必须定义对象,且创建对象时会有类的初始化。
而类方法和静态方法的引用不需定义对象,所以可以将一些和对象关系不大的接口定义为类方法或者静态方法。比如我下面写了个计算器的类,里面会有计算器的功能接口,比如加减乘除,可以将这些方法和对象绑定。
还有一些方法可能没必要创建对象再使用(通用的方法),比如查看帮助信息、查看版本号。可以将这些对象定义为类对象或者静态对象,这样直接通过类名就可以查看帮助信息、版本号了,岂不方便。
一句话就是,有些通用接口、和对象关系不大的可以定义为类方法、静态方法,类似于C中的extern修饰的全局函数。
示例:
import os
class Calculate(object):
def __init__(self):
pass
@classmethod
def help(cls):
print("help info:...")
@staticmethod
def get_version():
print("Calculate version: 0.1")
Calculate.help()
Calculate.get_version()
3- 类的封装
在类中,有些变量、方法为了安全、内部接口不对外呈现等原因,可以定义为私有变量、私有方法,用法参考1-
对于私有变量、私有方法访问比较麻烦,只能在类内进行访问。如果调试,需要在外面访问,可以使用访问器访问。
访问器分两个:setter和getter
语法:
@property
def getter的方法名(self):
pass
@setter的方法名.setter
def setter的方法名(self):
pass
示例:
对于类中的体重、年龄比较隐私,我们设置为私有变量,访问体重和设置体重示例如下:
import os
#初始类和对象
class People(object):
cnt = 0
def __init__(self, name, age, weight):
self.name = name
self.__age = age
self.__weight=weight
print("{0} init, self.name:{1}".format(self.__class__, self.name))#self.__class__指向类
#使用访问器访问私有变量
@property
def weight(self):
return self.__weight
@weight.setter
def weight(self, weight):
self.__weight = weight
Mic = People("kk", 17, 145)
#访问器访问私有变量
print("Mic's weight: {0}".format(Mic.weight))
#访问器设置私有变量
Mic.weight = 135
print("Mic's weight: {0}".format(Mic.weight))
4- 类的继承
可以把事物共性的部分封装成父类(基类),事物特有的部分封装成子类。
共有的变量、方法放在父类中,子类特有的变量、方法放在子类中。
初识类的继承
以例子说明。有个基类People,包含变量name,age
有个子类Student,继承自父类People。包含变量name、age、grade。
当我们创建一个对象student时,对于name、age这两个变量父类、子类都有,我们在初始化时使用super().__init__(父类、子类共有的变量),将这些父类子类共有的变量放到父类中去初始化。调用链为:子类__init__->父类__init__。
对于父类和子类共有的方法,如果子类由就用子类的,如果子类没有就用父类的,这叫做类的重写。比如Student和People都有借口who_am_i,当子类调用该接口时,打印子类该接口的内容。
import os
#初始类和对象
class People(object):
cnt = 0
def __init__(self, name, age):
self.name = name
self.age = age
print("class People init")
print("{0} init".format(self.__class__)) # self.__class__指向类
def who_am_i(self):
print("i am people")
class Student(People):
def __init__(self, name, age, grade):
super().__init__(name, age)
self.grade = grade
def who_am_i(self):
print("i am Student")
student = Student("kk", 15, 9)
print("name:{0}; age:{1}; grade:{2}".format(student.name, student.age, student.grade))
student.who_am_i()
类的多重继承
当一个子类继承自多个父类时,有继承顺序,按照顺序继承。
比如下面的Boy类,继承自父类Student和Worker,创建Boy的对象boy。当boy调用who_am_i时,由于Boy类中没有,需要继承自父类Student和Worker。
顺序是,先去Student中找,如果有则返回,没有采取Worker中找。
import os
#初始类和对象
class People(object):
cnt = 0
def __init__(self, name, age):
self.name = name
self.age = age
print("class People init")
print("{0} init".format(self.__class__)) # self.__class__指向类
def who_am_i(self):
print("i am people")
class Student(People):
def __init__(self, name, age, grade):
super().__init__(name, age)
self.grade = grade
def who_am_i(self):
print("i am Student")
class Worker(People):
def who_am_i(self):
print("i am worker")
class Boy(Student, Worker):
def __init__(self, name, age, grade, sex):
super().__init__(name, age, grade)
self.sex = sex
boy = Boy("kk", 15, 9, "boy")
boy.who_am_i()
5- 类的多态
类的多态在:继承+重写
用例子说话:
创建了基类People,两个子类Worker和Student,都继承自父类People。
创建3个对象:people、worker、student,worker和student会继承父类的公共变量。当worker和student调用who_am_i接口时将发生重写父类接口,调用各自类中的接口,这就是多态。
也就是Student和Worker虽然都继承自People,且这三个类都有同样的方法who_am_i,但是各自示例调用这个接口时,却只去自己的类中查找,这就是多态。
import os
#初始类和对象
class People(object):
cnt = 0
def __init__(self, name, age):
self.name = name
self.age = age
def who_am_i(self):
print("i am people")
class Student(People):
def __init__(self, name, age, grade):
super().__init__(name, age)
self.grade = grade
def who_am_i(self):
print("i am Student")
class Worker(People):
def __init__(self, name, age, work):
super().__init__(name, age)
self.work = work
def who_am_i(self):
print("i am worker")
people = People("hh", 15)
people.who_am_i()
student = Student("hh", 15, 9)
student.who_am_i()
student = Worker("hh", 15, "IT")
student.who_am_i()
类型检查:
接口:
isinstance(对象名,类名) 检查是否是类的对象
issubclass(类名1, 类名2) 检查类名1是否是类名2的子类
import os
#初始类和对象
class People(object):
cnt = 0
def __init__(self, name, age):
self.name = name
self.age = age
def who_am_i(self):
print("i am people")
class Student(People):
def __init__(self, name, age, grade):
super().__init__(name, age)
self.grade = grade
def who_am_i(self):
print("i am Student")
class Worker(People):
def __init__(self, name, age, work):
super().__init__(name, age)
self.work = work
def who_am_i(self):
print("i am worker")
people = People("hh", 15)
people.who_am_i()
student = Student("hh", 15, 9)
student.who_am_i()
student = Worker("hh", 15, "IT")
student.who_am_i()
print("{0} is object of {1}: {2}".format("student", "People", isinstance(student, People)))
print("{0} is object of {1}: {2}".format("student", "Worker", isinstance(student, Worker)))
print("{0} is object of {1}: {2}".format("people", "People", isinstance(people, People)))
print("{0} is {1} subclass:{2}".format("Student", "Worker", isinstance(Student, Worker)))
print("{0} is {1} subclass:{2}".format("Student", "People", isinstance(Student, People)))
鸭子类型
鸭子类型就是个概念,就是说一个事物有鸭子的特征,就可以叫做鸭子。
例子说话:
Animal、Dog、Cat、Car都有run方法,我们不关注类的特征(是否是动物),只关注是否有run方法。
这样做有什么好处呢?通过下面的例子我只理解到一点:虽然Car和其他的类不同,但是都有相同名称的方法,我们可以把相同的接口调用封装起来,这样就做到了和类的隔离(二次封装),是否是这样?
import os
#父类:Animal
class Animal(object):
def run(self):
print("animal run...")
#子类:Dog
class Dog(Animal):
def run(self):
print("dog run...")
#子类:Cat
class Cat(Animal):
def run(self):
print("cat run...")
#子类:Cat
class Car(Animal):
def run(self):
print("car run...")
def go(animal):
animal.run()
go(Animal())
go(Dog())
go(Car())
6- python根类-object
python的根类为object,我们创建的类都继承自根类object。
object有很多方法,这里简单介绍下__str__和__eq__。
__str__:执行print时,会调用__str__,我们可以定制化打印类
__eq__:执行==时会调用__eq__,我们可以定制化对象相等的条件。
import os
class People(object):
cnt = 0
def __init__(self, name, age):
self.name = name
self.age = age
#print函数会调用__self__接口
def __str__(self):
print("i am re-write print func")
template = 'Person [ name={0}, age={1} ]'
s = template.format(self.name, self.age)
return s
#==运算符会调用__eq__接口
def __eq__(self, other):
if self.name == other.name and self.age == other.age :
return True
else:
return False
python = People("python", 15)
print(python)
Python = People("python", 15)
print(python == Python)
7- 枚举类
和c一样python也有枚举类型。
初始枚举类型:
这里我们可以把枚举变量的值可以为非整数,且枚举类中的两个变量值可以一样。如果我们想要使枚举类的值为整数、枚举类中变量值不一样,可以使用限制型枚举类
import os
import enum
class WeekDays(enum.Enum):
MONDAY = 1
TUESDAY = 2
WEDNESDAY = 3
THURSDAY = 4
FRIDAY = 5 #FRIDAY = 5
day = WeekDays.FRIDAY
print(day) #输出 WeekDays.FRIDAY
print(day.value) #输出 5
print(day.name) #输出 FRIDAY
限制性枚举类:
import os
import enum
@enum.unique #限制性枚举类
#枚举类的值为整数
class WeekDays(enum.IntEnum):
MONDAY = 1
TUESDAY = 2
WEDNESDAY = 3
THURSDAY = 4
FRIDAY = 5 #FRIDAY = 5
day = WeekDays.FRIDAY
print(day) #输出 WeekDays.FRIDAY
print(day.value) #输出 5
print(day.name) #输出 FRIDAY