面向对象
特点:封装、继承、多态
- python 一切皆对象
- 所有的数据类型都是一个类
- 所有的类型值都是一个具体的对象
自定义类
-
回想函数
def func(): pass
-
类的定义
class 类名: def __init__(self, *args, *kwargs): 属性 = 'a' def #属性的调用 类名.属性
类属性的补充
一:我们定义的类的属性到底存到哪里了?有两种方式查看
dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值
二:特殊的类属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)
类属性的补充
对象的功能
- 调用属性
- 调用方法
类名的功能
类的组合
1. 继承性
-
父类(基类、超类)
-
子类(派生类)
-
继承是创建新类的方式,一个类可以继承一个或多个父类
class A:pass class B:pass class A_son(A):pass class AB_son(A, B):pass
-
.__bases__
查看子类继承的父类print(A_son.__bases__) #结果 (<class '__main__.A'>,) #所有类的基类 -新式类 print(A.__bases__) #结果 (<class 'object'>,) #object类的最顶端的类
- python3中没有没有父类的类
-
小练习
#狗类 吃 喝 看门 #鸟类 吃 喝 下蛋 #动物类 class Animal: def eating(self): print('我正在吃') def drink(self): print('我正在喝水') #狗类 class Dog(Animal): def kan_men(self): print('我能看门') #鸟类 class Brid(Animal): def xia_dan(self): print('我能下蛋') #实例化狗 xiao_hei = Dog() #实例化鸟 tuo_niao = Brid() xiao_hei.drink() xiao_hei.eating() xiao_hei.kan_men() tuo_niao.drink() tuo_niao.eating() tuo_niao.xia_dan() #结果 我正在喝水 我正在吃 我能看门 我正在喝水 我正在吃 我能下蛋
-
子类中的方法会覆盖父类中的方法
-
子类中和父类具有相同方法时又想调用父类的方法
-
继承和派生
单继承
- 派生属性
#创建一个父类,具有name属性
class Father:
def __init__(self, name):
self.name = name
#创建一个子类,具有name和age属性
class Chrld(Father):
def __init__(self, age):
Father.__init__(self, name) #继承父类的属性
self.age = age #派生子类特有的属性
- 派生方法
- 父类没有的方法子类有的方法叫派生方法
- 如果父类里有子类的方法,子类的方法会覆盖父类的方法
-
super()
关键字继承-
super
可以在类的外部使用,调用父类的方法super(Chidren, Chidrend的实例).父类方法名(*args, *kwargs)
-
super(类名, self).方法名(*args, *kwargs)
-
等同于
类名.方法名(self, *args, *kwargs)
-
super()
遵循广度优先继承class Animal: def __init__(self, name): self.name = name class Dog(Animal): def __init__(self, age) super().__init__(name) #继承父类的__init__方法, #相当于Animal.__init__(self, name), #这个方法的全写是super(Animal, self).__init__(name) self.age = age
-
-
类的继承和抽象
- 抽象即类似比较像的
- 继承是抽象的结果
- 继承是类和类的关系
多继承
- 新式类继承遵循广度优先继承
- 钻石继承
- 漏斗继承
- 小乌龟继承
- 经典类是深度优先继承
- 经典类指python2.x
- pthon3均是新式类
接口类和抽象类
- 接口类和抽象类都是对面向对象开发的规范
接口类
-
继承接口类必须具有接口类中被装饰的函数
#定义一个接口类(规范类函数) from abc import absrtactmethod, ABCMeta class Jie_Kou(metaclass=ABCMeta) #加上一个参数 @abstractmethod #装饰器 def func1(self): pass @abstractmethod #装饰器 def func2(self): pass
-
接口隔离原则
- 使用多个单一的接口,而不使用一个总接口。即客户端不应该依赖的那些不需要的接口
抽象类
- 抽象类也是一种规范
- 一般是单继承
- 子类继承的父类功能一致
- 多继承的情况由于功能比较复杂,所以不容易抽象出相同功能的类
2. 多态性
- 一个事物有多种形态
- 一个类有多种形态
- python语言是动态强类型语言
- 鸭子类型
- 不崇尚根据继承所带来的相似
- 我只是自己实现我自己的代码就可以了
- 如果两个类恰好相似并不产生兄弟关系,而是鸭子类型
3. 封装性
- 将变量和函数都放进一个类中
封装的私有方法和私有属性
-
利用双下划线来定义私有属性和方法
-
所有的私有变量和私有方法是人为不想让你在类的外部使用,不是不能调取而是不想让你调取
class Person(): def __init__(self, name, age): self.name = name self.__age = age #私有属性,只能内部调,外部不能调取 def func1(self): #用公有方法调用私有属性 print(name) print(__age) #在类的内部,正常调用 def __func2(self): #私有方法,只能内部调用 pass #实例化对象 alex = Person() alex.name alex.__age #报错,找不到这个属性 alex._Person__age #正常调用,调用类中私有属性__age alex.func1() alex.__func2() #报错,找不到这个方法 alex._Person__func2() #正常调用
-
保护属性,不想让外界直接更改
class Protect(): def __init__(self, name) self.__name = name #将属性name私有化 def get_name(): #获取__name的值 return self.__name def set_name(newName): #更改__name的值 self.__name = newName return self.__name
-
保护属性不想让子类继承
class Father(): def __init__(self, name): self.__name = name class Child(Father): def __init__(self, age): super.__init__(name) #这一步会报错,父类的私有属性子类无法调用 child = Child() #报错,无法找到_Child__name
封装里的内置函数
@property
将函数伪装成属性
@私有变量名.setter
设置私有变量的值
@私有变量名.deleter
使用del
关键字调用修饰的方法
from math import pi
#定义一个圆类
class Circle():
def __init__(self, r)
self.r = r
#圆面积
@property
def area(self):
return self.r**2*pi
@property
#圆周长
def perimeter(self):
return 2*self.r*pi
#实例化一个圆
circle = Circle(1) #实例化半径为1的圆
print(circle.area) #直接调用圆面积计算的方法返回圆面积
print(circle.perimeter) #直接调用圆周长的方法返回圆周长
伪装成属性后修改属性的值
- 通过这种方法修改了私有变量的值
- 被修饰的两个方法的名最好和私有变量名一样,这样伪装的才能彻底
-
私有变量的查看、修改、删除
class Father(): def __init__(self, name): self.__name = name #查看 @property #伪装装饰方法成属性 def name(self): return self.__name #修改 @name.setter #提供可修改的方法,装饰器的名字必须是伪装方法的名字.setter def name(self, newName): self.__name = newName #删除 @name.deleter #提供del调用的方法,并不提供删除 def name(self, newName): print('测试的代码,测试不删除') #这是测试的代码 del self__name #这里才是提供删除的原因 c = Father(1) print(c.name) c.name = 2 #可以修改__name的属性 print(c.name) del c.name #使用del可以调用@deleter装饰的函数 print(c.name) #结果 1 2 测试的代码,测试不删除 报错,找不到_Father__name
-
类方法classmethod
-
只涉及静态属性的时候使用
#建立一个货物的类 class Goods(): __discount = 0.5 #这个类具有折扣的通用属性 def __init__(self, name, price): self.name = name #商品名 self.__price = price #商品价格,私有变量,不想让其他人看到 @property #伪装属性用于查看 def price(self): return self.__price * Goods.__discount @classmethod #类方法 def change_discount(cls, new_discount): #cls参数指代Goods,指代类名,可以是其他参数但是不建议改变 cls.__discount = new_discount #直接外部修改类的通用属性 Goods.change_discount(0.8) #将折扣0.5变成0.8,直接调用类名.函数名修改类方法
静态方法staticmethod
-
可以省略参数self创建类中的方法
-
在完全面向对象的程序中
-
如果一个函数即和对象没有关系也和类没有关系
-
静态方法和静态属性对象都能够调用的,不过一般情况下推荐用类名调用
class Login(): def __init__(self, name, password): self.name = name self.password = password @staticmethod #静态方法 def get_us_pw(): #注意这里没有参数self user = input('User:') password = input('Password') Login(name, password) #调用 Login.get_us_pw()