1 概述
1.1 编程方式
(1)面向过程:根据业务逻辑从上到下写代码
(2)函数式:将某功能代码封装在函数中,需要时直接调用
(3)面向对象:将函数进行分类和封装,让开发更好更快更强
Python使用类(class)和对象(object)进行面向对象编程。
面向对象三大特性:
(1)继承:解决代码的复用性问题
(2)封装:对数据属性严格控制,隔离复杂度
(3)多态性:增加程序的灵活性与可扩展性
1.2 类和对象
类是对象的类型,具有相同属性和行为事物的统称。类是抽象的,使用中会找到这个类的一个具体存在,ex:动物是类,狗是具体的。
万物皆对象,对象拥有自己的特征和行为。 ex:狗
类与对象的关系:类是对象的类型,对象是类的实例。类是抽象的概念,而对象是能够摸得着、看得见的实体。二者相辅相成,谁也离不开谁。
2 定义类
类的组成部分:类型、属性、方法
Class
属性列表
方法列表
class Person(object):
def __init__(self, name): # 构造方法,实例化时自动调用
print('我是构造方法,在实例化的时候调用!')
self.name = name
def SayHi(self): # 方法就是函数
print('大家好,我是%s!' % self.name)
p = Person("Tom") # 实例化对象 我是构造方法,在实例化的时候调用!
p.SayHi() # 大家好,我是Tom!
2.1 __init__()方法
__init__( )是一个特殊方法属于类的专用方法,称为类的构造函数或初始化方法,方法的前面和后面都有两个下划线。
每当创建类的实例化对象时,__init__( )方法默认运行,作用是初始化已实例化的对象
在方法定义中,第一个参数self必不可少,类方法和普通函数的区别就是self,但不是Python关键字,完全可以用其他单词取代,只是按照惯例和标准的规定,推荐使用self。
2.2 类属性和实例属性
类属性/类变量:在整个实例化的对象中是公用的,类变量定义在类方法外,通常不作为实例变量使用,函数中的使用格式为:类名.类属性。
实例属性/变量:定义在类方法中的变量,只作用于当前实例的类,访问方法:实例化对象名.属性
class Person(object):
country = 'China'
def __init__(self, name): # 构造方法,实例化时自动调用
self.name = name
def SayHi(self): # 方法就是函数
print('大家好,我是%s来自%s!' % (self.name, Person.country))
pr1 = Person("Tom") # 实例化对象 我是构造方法,在实例化的时候调用!
pr2 = Person('Frank')
pr1.SayHi() # 大家好,我是Tom来自China!
pr2.SayHi() # 大家好,我是Frank来自China!
2.3 内置类属性
__dict__:类的属性(包含一个字典,由“类的属性名.值”组成),实例化类名.__dict__
__doc__:类的文档字符串,实例化类名.__doc__
__name__:类名,实现方式:类名.__name__
__bases__:所有父类构成元素(包含一个所有父类组成的元组)
3 继承和多态
class继承,新的class称为子类(Subclass),被继承的class称为基类、父类或超类。子类继承了父类的所有属性和方法,同时还可以定义自己的属性和方法。
class Animal():
def __init__(self, name, food):
self.name = name
self.food = food
def Eat(self):
print('%s喜欢吃%s' % (self.name, self.food))
class Dog(Animal):
def __init__(self, name, food, cry):
super(Dog, self).__init__(name, food)
self.cry = cry
def Cry(self):
print('%s这样叫:%s' % (self.name, self.cry))
class Cat(Animal):
def __init__(self, name, food, cry):
super(Cat, self).__init__(name, food)
self.cry = cry
def Cry(self):
print('%s这样叫:%s' % (self.name, self.cry))
dog = Dog('小狗', '骨头', '汪汪')
dog.Eat() # 小狗喜欢吃骨头
dog.Cry() # 小狗这样叫:汪汪
cat = Cat('小猫', '鱼', '喵喵')
cat.Eat() # 小猫喜欢吃鱼
cat.Cry() # 小猫这样叫:喵喵
多继承:一个子类可以继承多个父类是多继承
Python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。
class Base(object):
def play(self):
print('Base is playing!')
class A(Base): # 继承Base
def play(self): # 自动覆盖父类的此方法
print('A is playing')
class B(Base): # 继承Base
def play(self):
print('B is playing')
class C(A, B): # 继承A,B
# pass # 采用覆盖后的方法:A is playing
def play(self): # 调用父类中的方法:Base is playing!
Base.play(self)
c = C()
c.play()
4 访问限制
要让内部属性或者方法不被外部访问,可以把在属性或者方法的名称前加上单下划线_, 或者在前面加双下划线__,或者两边加双下划线。
_foo”,只允许类本身和子类可以访问;
__foo”,外部不可通过“对象.属性名”来访问或者更改,实际将其转化成了“_类名__属性名”;
__foo__”:系统方法或函数。
class Swan:
"""天鹅类"""
_neck_swan = "天鹅的脖子很长" # 保护类型的属性
def __init__(self):
print("__init__(): ", Swan._neck_swan) # 访问保护类型的属性
swan = Swan() # 实例化Swan类的实例(对象)
print("直接访问:", swan._neck_swan) # 通过实例名访问保护类型的属性
# __init__(): 天鹅的脖子很长
# 直接访问: 天鹅的脖子很长
5 类方法与静态方法
5.1 实例方法
self”,通过它来传递实例的属性和方法(也可以传类的属性和方法);
调用:只能由实例对象调用。
5.2 类方法
定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);
调用:实例对象和类对象都可以调用。
应用场景
假设我有一个学生类和一个班级类,想要实现的功能为:
执行班级人数增加的操作、获得班级的总人数;
学生类继承自班级类,每实例化一个学生,班级人数都能增加;
最后,我想定义一些学生,获得班级中的总人数。
5.3 静态方法
定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;
调用:实例对象和类对象都可以调用。
静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护。
譬如,我想定义一个关于时间操作的类,其中有一个获取当前时间的函数。
import time
class TimeTest(object):
def __init__(self, hour, minute, second):
self.hour = hour
self.minute = minute
self.second = second
@staticmethod
def showTime():
return time.strftime("%H:%M:%S", time.localtime())
print(TimeTest.showTime()) # 13:19:34
t = TimeTest(2, 10, 10)
nowTime = t.showTime()
print(nowTime) # 13:19:34