说话简洁渡
说话清楚
表达清楚
pycharm 默认模板 时间,作者,文件,邮箱,使用的环境
- 多态
- 什么是多态
- 多态在python 中的应用
- 鸭子类型
- 封装
- 广义的封装
- 狭义的封装
1. 私有的
1.原理
2.使用方式,场景
- property
- classmethod
- staticmethod
- issubclass
- isinstance
继承 提高代码的重用性
作用:当你开始编写两个类时,出现重复代码,要通过继承来简化代码,把重复的代码放在父类里。
这之后继承又规范代码,要求继承父类的子类都实现相同的方法:抽象类,接口。
单继承
重用性,减少代码的重复,子类复用父类的方法
派生:子类在父类的基础上又创建了自己的新的方法和属性
子类中有父类的同名方法,只用子类
还希望用父类中的方法:父类,super调用
派生:子类在父类的基础上又创建了自己的新的方法和属性
抽象类 :只能被继承不能被实例化。作为模板,规则
from abc import ABCMeta,abstractmethod #其他函数写在其他的地方,不在内存里,需要从硬盘上读出来。导入模块
class A(metaclass=ABCMeta):
@abstractmethod
def func(self):pass
多继承
python c++ 有
java / c# 没有
每个类中有每个类能完成的方法
创建子类的时候只需要挑选和我相符的父类来继承就能够完成父类的功能
接口类:java中额数据类型
经典类和新式类的区别
经典类 不主动继承object 没有mro方法没有super继承 深度优先
新式类 主动继承object mro super 继承的时候 广度优先
py2 py3的区别
编码,经典新式类区别
class Student:
def __init__(self):
self.name = "alex"
def name(self):
print(1111)
alex = Student()
print(alex.name()) #报错
"只有被对象调用的类中的方法才能被成为一个方法"
class A:
def func(self):pass
a = A()
print(a.func)
print(A.func)
from types import MethodType,FunctionType
print(isinstance(a.func,MethodType))
print(isinstance(a.func,FunctionType))
print(isinstance(A.func,FunctionType))
print(isinstance(A.func,MethodType))
什么是构造函数
__new__
什么是初始化函数__init__
类的方法是动态属性,绑定到所有对象上的
组合指的是,在一个类中以另一个类的对象作为数据属性
多态
什么是多态
一个类表现出的多种状态,通过继承实现的。一个父类多个子类即可表现多态。
"Animal 类表现出了Dog,Cat两种形态"
class Animal:pass
class Dog(Animal):pass
class Cat(Animal):pass
wc = Dog()
多个子类同一个父类,在传参时用父类类型识别就可规避强类型语言检查的限制。
所有的类都是object类的子类,所以python处处用到多态
多态是继承的内容,为什么要把多态单独列出来
在java中运用多态,来解决传参数的时候,数据类型的规范为题
class ApplePay:
def pay(self):pass
class Alipay:
def pay(self):pass
def pay(obj,money):
obj.pay()
# Java 中函数传参是有类型限制必须要传递准确的类型,强数据类型
# 强数据类型 帮助我们规避了错误
a = "123"
a = str("123")#str 是一个类,str()就是实例化,a是一个对象,是str类的对象,a的type就是str
python处处是多态,默认object
在经典类不是object 那是否无法多态,但是py2照样可以用
在经典的类中也有类似的机制,但是我们不知道,init也正常执行。
object 是p3暴露出来的细节
鸭子类型
多态在python中的体现,就是通过鸭子类型
def len(obj)
len()# str list tuple dict set range(3)
index()
# 不是明确的通过继承实现多态,传递数据类型,而是通过模糊的概念来判断这个方法能不能接受数据类型的参数
# print()所有的对象都是鸭子类型
"鸭子类型只需要你像就可以"
"以下是明确的继承关系,继承->是"
class len_type():pass
class str(len_type):pass
class list(len_type):pass
class tuple(len_type):pass
class dict(len_type):pass
class set(len_type):pass
class iterator(len_type):pass
白鹅类型 goose typing
白鹅类型指的是,只要cls是抽象类,即cls的元类是abc.ABCMeta 就可以使用isinstance(obj,cls)
借助白鹅类型,可以使用抽象基类明确声明接口,而且类可以子类化抽象基类或使用抽象基类注册(无需再继承关系中确立静态的强链接)宣称它实现了某个接口
封装
广义上的封装
class 类名:
def 方法1(self):pass
是为了只有这个类的对象才能使用定义在类中的方法
狭义上的封装
把一个名字藏起来
class Goods:
__discount = 0 #私有的静态变量
print(Goods.__discount) #在类的外部不能引用私有的静态变量
类中的静态变量和方法名在程序加载的过程中就已经执行完了,不需要等待调用
在这个类加载完成之前,Goods这个名字还没有出现在内存空间中
私有的静态属性可以在类的内部使用,用来隐藏某个变量的值
"私有变量在类中进行了变形,_类名_私有变量"
class Goods:
__discount = 0
print(Goods.__dict__)
print(Goods._Goods__discount) # 编程规范的角度出发,我们不能在类的外部使用私有的变量
为什么要定义一个私有变量?
不想让用户看到这个值
不想用户修改这个值
我想让你修改这个值的时候有限制
有些方法或者属性不想被子类继承
类中的私有成员
私有的静态变量
私有的对象属性
私有的方法
"保证传进去的属性不能被修改"
class Student:
def __init__(self,name,age):
self.__name = name
self.age = age
def name(self):
return self.__name
zhuge = Student("诸葛",20)
print(zhuge.name())
print(zhuge.age)
zhuge.age = "aaaa"
print(zhuge.age)
"原本的值藏起来,返回加工后的值"
class Goods:
__discount = 0.7
def __init__(self,name,price):
self.name = name
self.__price = price
def price(self):
return self.__price * Goods.__discount
apple = Goods("APPLE",5)
print(apple.price())
"用户的密码不能以明文的形式存储"
"加密的方法也不想让人知道"
"只暴露加密方法的结果"
class User:
def __init__(self,username,password):
self.user = username
self.__pwd = password
self.pwd = self.__getpwd()
def __getpwd(self):
return hash(self.__pwd)
obj = User("alex","alex3714")
print(obj.user,obj.pwd)
私有变量能不能在外部被定义?
class A:
__country = "China" # 只有在类的内部会发生变形
print(__country) #不仅是在定义还是调用
print(A.__dict__)
A.__Language = "Chinese"
print(A.__dict__)
私有变量能不能被继承?
class A:
__country = "China"
def __init__(self):
self.__name = name
class B(A):
print(__country) #找不到
print(_A__country) #找不到
print(A._A__country)
"有些方法或者属性不想被子类继承"
class A:
__country = "China"
def __init__(self,name):
self.__name = name #_A__name
class B(A):
def get_name(self):
return self.__name # _B__name
b = B("alex")
b.get_name()
print(b.__dict__)
class A:
vv = 'd'
__country = "China"
def __init__(self,name):
self.__name = self.vv
class B(A):
def get_name(self):
return self._A__name
b = B("alex")
print(b.get_name()) #调用到
print(b.__dict__)
property
装饰器
装饰器的分类
装饰方法 :property
装饰函数
装饰类
@property 将一个方法伪装成属性
class Student:
def __init__(self,name,age):
self.__name = name
self.age = age
@property
def name(self):
return self.__name
zhuge = Student("诸葛",20)
print(zhuge.name)
from math import pi
class Circle:
def __init__(self,r):
self.r = r
#self.area = self.r ** 2 * pi
#或者
#self.area = self.area() #为什么不这么写?万一这个半径不是传入的值aera改变不了了,因为他只在实例化中计算出
@property
def area(self):
return self.r ** 2 *pi
@property
def perimiter(self):
return 2 * self.r *pi
class Animal:
def __init__(self,name,aggressivity,life_value):
self.name = name
self.aggressivity = aggressivity
self.life_value = life_value
def eat(self):
print("%s is eating" % self.name)
class Dog(Animal):
def __init__(self,breed):
self.breed = breed
def bite(self,name,aggressivity,life_value):
super().__init__(name,aggressivity,life_value)
print(self.name)
pass
a = Dog("a")
a.bite("d","b","c")
print(a.__dict__)
依赖倒置原则:
高层模块不应该依赖低层模块,二者都应该依赖其抽象;
抽象不应该应该依赖细节;
细节应该依赖抽象。
换言之,要针对接口编程,而不是针对实现编程
抽象类与接口类的区别
抽象类的本质还是一个类,指的是一组类的相似性。
包括数据属性和函数属性。
而接口只强调函数属性的相似性。
抽象类是介于类和接口直接的一个概念,
同时具备类和接口的部分特性。用来实现归一化
接口隔离原则:
使用多个专门的接口,而不使用单一的总接口。
即客户端不应该依赖那些不需要的接口。
MRO列表就是一个简单的所有基类的线性顺序列表
C3线性化算法来实现的
鸭子类型
如果想编写现有对象的自定义版本,可以继承该对象
也可以创建一个外观和行为像,
但与它无任何关系的全新对象,
后者通常用于保存程序组件的松耦合度。
封装的好处
1. 将变化隔离
2. 便于使用
3. 提高复用性
4. 提高安全性
def add(n,i):
return n+i
def test():
for i in range(4):
yield i
g = test()
for n in [1,10]:
g=(add(n,i) for i in g)
print(list(g))
---------
"输出"
[20, 21, 22, 23]
---------
"简化版:"
"将for循环拆解成步骤运算"
def add(n,i):
return n+i
def test():
for i in range(4):
yield i
g = test()
n = 1
g = (add(n,i) for i in g)
n =10
g = (add(n,i) for i in g)
print(list(g))
"简化版:"
"将for循环拆解成步骤运算"
def add(n,i):
return n+i
def test():
for i in range(4):
yield i
g = test()
n = 1
g1 = (add(n,i) for i in g) "g是test实例化的生成器,而这个赋值右边的表达式表示的也是生成器,我们将其重新命名为g1。"
n =10
g2 = (add(n,i) for i in g1) "由于生成器g通过表达式转变成了g1,那么我们相应的改变in后的表达式为g1,以及赋值左边的变量为g2"
print(list(g2))
"再简化"
"现在我们有了两个生成器,并没有执行
"仅仅是在全局空间里声明了变量名与生成器地址的对应关系"
"所以n并没有直接赋值。"
"当list方法调用时才会通过隐含的__next__()去计算生成器的逻辑"
"那时生成器才会真正的开辟临时空间"
"由于空间内部的n是调用的全局n,所以g1,g2两个生成器n此时传递的是最后一次的赋值,10"
"add方法就是求两个数的和所以,可用固定表达式代替"
# def add(n,i):
# return n+i
def test():
for i in range(4):
yield i
g = test()
n = 1
n =10
g1 = (10+i for i in g)
g2 = (10+i for i in g1)
print(list(g2))
class StarkConfig(object):
def __init__(self,num):
self.num = num
def changelist(self,request):
print(self.num,request)
def run(self):
self.changelist(999)
class RoleConfig(StarkConfig):
def changelist(self,request):
print(666,self.num)
config_obj_list = [StarkConfig(1),StarkConfig(2),RoleConfig(3)]
config_obj_list[1].run()
config_obj_list[2].run()