面向对象
面向对象
面向对象编程:是一类相似功能函数的集合,使你的代码更清晰化,更合理化
1.面向对象的结构(第一部分:静态属性 属性 静态变量 静态字段)/(第二部分:方法 函数 动态属性)
class Stu:
study = "学习"#静态属性
exam = "考试"#静态属性
def work(self):#动态属性
print("每天上课")
def homework(self):
print("写作业")
class是类的关键字,即为定义一个类
Stu为类名 使用大驼峰命名风格 首字母大写
2.类名操作静态属性
1查看类中的内容:.__dict__ 类名.__dict__
class Stu:
study = "学习"#静态属性
exam = "考试"#静态属性
def work(self):#动态属性
print("每天上课")
def homework(self):
print("写作业")
print(Stu.__dict__)
#{'__module__': '__main__', 'study': '学习', 'exam': '考试', 'work': <function Stu.work at 0x000001280185CBF8>, 'homework': <function Stu.homework at 0x000001280185CC80>, '__dict__': <attribute '__dict__' of 'Stu' objects>, '__weakref__': <attribute '__weakref__' of 'Stu' objects>, '__doc__': None}
2.万能的点.
class Stu:
study = "学习"#静态属性
exam = "考试"#静态属性
def work(self):#动态属性
print("每天上课")
def homework(self):
print("写作业")
print(Stu.__dict__)
查
print(Stu.study)
print(Stu.exam)
增
Stu.close = "校服"
print(Stu.close)
删
del Stu.close
print(Stu.__dict__)
改
Stu.exam = "不想考试"
print(Stu.exam)
3.类名操作动态方法
class Hun:
mind = "有点思想"
dic = {}
l1 = []
def work(self):
print("人类会工作")
def too(self):
print("人类会使用工具")
hun.work(11)#11为参数,work中的self需要接受一个参数
4.从对象的角度研究类
类名+()就是一个实例化过程 就会实例化成一个对象
class Human:
mind="有思想"
language = "使用语言"
def __init__(self,name,sex,age,hobby):
#self就是类中方法的第一个位置参数,self 和obj指向的同一内存地址 name,sex,age,hobby就是self封装的四个属性
self.姓名=name
self.性别 = sex
self.年龄 = age
self.爱好 = hobby
print(self)#<__main__.human object at 0x00000258965EDC18>
#self 和obj指向的同一内存地址
obj = Human("barry","男",18,"运动")
obj.职业 = "it"#增
obj.性别 = "女"#改
del obj.性别 #删
print(obj.年龄)#查
print(obj.__dict__)
print(obj)#<__main__.Human object at 0x00000258965EDC18>
1.在内存中开辟了一个对象空间
2.自动执行类中的__init__方法,并将这个对象空间(内存地址)传给了__init__方法的第一个位置参数self。
3.在__init__ 方法中通过self给对象空间添加属性
一个类实例化多个对象
class Human:
mind="有思想"
language = "使用语言"
def __init__(self,name,sex,age,hobby):
self.姓名=name
self.性别 = sex
self.年龄 = age
self.爱好 = hobby
obj1 = Human('小胖','男',20,'美女')
obj2 = Human('相爷','男',22,'肥女')
print(obj1.__dict__)
print(obj2.__dict__)
#{'姓名': '小胖', '性别': '男', '年龄': 20, '爱好': '美女'}
{'姓名': '相爷', '性别': '男', '年龄': 22, '爱好': '肥女'}
继承
继承的有点也是显而易见的:
1,增加了类的耦合性(耦合性不宜多,宜精)。
2,减少了重复代码。
3,使得代码更加规范化,合理化
# 单继承
class People:
mind = "有思想的"
def __init__(self,name,age):
self.name = name
self.age = age
class Animal(People):
mind = "无脑的"
People为父类,基类,超类,Animal为子类,派生类
obj = People("八戒",36)
obj1 = Animal("八戒",36)
实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。
先要执行自己类中的方法,自己类没有才能执行父类中的方法
print(obj.mind)
print(obj1.mind)
# 同时执行类和父类的方法
# 方法一
class Ainmal:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
class People:
def __init__(self,name,age,sex,hobby): #父类方法重构 增加hobby是为了区别人类和动物的区别,但还要用之前人和动物的共同属性,在原来的基础上增加hobby
Ainmal.__init__(self,name,age,sex) #调用Ainmal中的__init__
self.hobby = hobby #添加hobby
obj = Ainmal("八戒",36,"男")
obj1 = People("八戒",36,"男","女")
print(obj.__dict__)
{'name': '八戒', 'age': 36, 'sex': '男'}
print(obj1.__dict__)
{'name': '八戒', 'age': 36, 'sex': '男', 'hobby': '女'}
# 方法二
class Ainmal:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
class People(Ainmal):
def __init__(self,name,age,sex,hobby):
super(People,self).__init__(name,age,sex) # 完整版
super().__init__(name,age,sex) # 简写版
self.hobby = hobby
obj = People("八戒",36,"男","女")
print(obj.__dict__)
{'name': '八戒', 'age': 36, 'sex': '男', 'hobby': '女'}
class Ainmal:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print("吃饭")
class People(Ainmal):
def __init__(self, name, age, sex, hobby):
super(People, self).__init__(name, age, sex) # 完整版
super().__init__(name, age, sex) # 简写版
self.hobby = hobby
def eat(self):
super().eat() #调用父类中的方法
print(f"{self.name}吃饭")
obj = People("八戒", 36, "男", "女")
print(obj.__dict__)
obj.eat()
# 吃饭
# 八戒吃饭
# 单继承练习
# 第一题
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
class Foo(Base):
pass
obj = Foo(123)
obj.func1()
"""
先在本类中找 Foo为本类
1.obj = Foo(123)实例化对象,自动执行__init__方法,此时self = obj,num = 123
2.执行obj.func1(),首先在Foo的类中找func1,Foo中没有,到父类中找func1,执行func1 ,打印123
"""
# 第二题
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
class Foo(Base):
def func1(self):
print("Foo. func1", self.num)
obj = Foo(123)
obj.func1()
"""
先在本类中找 Foo为本类
1.obj = Foo(123)实例化对象,自动执行__init__方法,此时self = obj,num = 123
2.执行obj.func1(),首先在Foo的类中找func1,Foo有,则执行func1 ,打印 Foo. func1 123
"""
# 第三题
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
self.func2()
def func2(self):
print("Base.func2")
class Foo(Base):
def func2(self):
print("Foo.func2")
obj = Foo(123)
obj.func1()
"""
先在本类中找 Foo为本类
1.obj = Foo(123)实例化对象,自动执行__init__方法,此时self = obj,num = 123
2.执行obj.func1(),首先在Foo的类中找func1,Foo中没有,去父类中找func1,父类中有,则执行func1 ,打印123
3.继续执行func2 也是先去Foo中找func2 找到则执行,找不到则在父类中继续找 结果 123 Foo.func2
"""
# 第四题
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
self.func2()
def func2(self):
print(111, self.num)
class Foo(Base):
def func2(self):
print(222, self.num)
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
obj.func2()
"""
1.Base(1), Base(2), Foo(3)实例化,num分别为1,2,3
2.循环列表 1.Base(1)在执行Base(1)中的func2中内容 打印111 1 2.Base(2)中的func2中内容 打印111 2 3.执行Foo(3)在Foo中内容 222 3
"""
多继承
在python2x版本中存在两种类.:
⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
python3x版本中只有一种类:
python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
class E:
pass
class F(D, E):
pass
class G(F, D):
pass
class H:
pass
class Foo(H, G):
pass
MRO: Foo-> H -> G -> F -> E -> D -> B -> A -> C(看图)
print(Foo.mro())******(直接计算)
原则:从头开始. 从左往右. ⼀条路跑到头, 然后回头. 继续⼀条路跑到头. 就是经典类的MRO算法.
封装 和 多态
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
所以,在使用面向对象的封装特性时,需要:
- 将内容封装到某处
- 从某处调用被封装的内容封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
封装
class foo:
def __init__(self,name,age):
self.name = name
self.age = age
obj1 = foo("wupeiqi",18)
obj2 = foo("alex",73)
通过对象直接调用被封装里的内容
print(obj1.name)
print(obj1.age)
print(obj2.name)
print(obj2.age)
class foo:
def __init__(self,name,age):
self.name = name
self.age = age
def info(self):
print(self.name)
print(self.age)
间接通过self调用
obj1 = foo("wupeiqi",18)
obj2 = foo("alex",73)
obj1.info()
obj2.info()
多态
多态,同一个对象,多种形态。python默认支持多态。
ython中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。
对于代码上的解释其实很简答:
class A:
def f1(self):
print('in A f1')
def f2(self):
print('in A f2')
class B:
def f1(self):
print('in A f1')
def f2(self):
print('in A f2')
obj = A()
obj.f1()
obj.f2()
obj2 = B()
obj2.f1()
obj2.f2()
# A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。
# 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。
# 这样的例子比比皆是:str tuple list 都有 index方法,这就是统一了规范。
# str bytes 等等 这就是互称为鸭子类型。
类的约束
提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了.
这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错.
方法1*****
class payment:
def pay(self,money):
raise Exception("子类没有引用pay方法")
#手动添加报错信息
class qqpay(payment):
def pay(self,money):
print(f"使用QQ支付{money}")
class wechatpay(payment):
def pay(self,money):
print(f"使用QQ支付{money}")
class Alipaypay(payment):
def zhifu(self,money):
print(f"使用支付支付{money}")
def pay(obj,money):统一接口(支付接口,方便其他文件的互相调用)
obj.pay(money)
obj1 = qqpay()
obj2 =wechatpay()
obj3 =Alipaypay()
pay(obj1,100)
pay(obj2,100)
pay(obj3,100)
方法2:抽象类,接口类 :强制指定规则
from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self,money):
pass
class qqpay(Payment):
def pay(self,money):
print(f"使用QQ支付{money}")
class wechatpay(Payment):
def pay(self,money):
print(f"使用QQ支付{money}")
class (Payment):
def pay(self,money):
print(f"使用支付宝支付{money}")
def pay(obj,money):
obj.pay(money)
obj1 = qqpay()
obj2 =wechatpay()
obj3 =Alipaypay()
pay(obj1,100)
pay(obj2,100)
pay(obj3,100)
super深度深入了解
class A:
def f1(self):
print('in A')
class Foo(A):
def f1(self):
super().f1()
print('in Foo')
class Bar(A):
def f1(self):
print('in Bar')
class Info(Foo,Bar):
def f1(self):
super().f1()
print('in Info f1')
print(Info.mro())# Info--》Foo--》Bar--》A--》object
obj = Info()
obj.f1()
1.实例化一个对象
2.先在info的类中找f1 info中有f1 执行super().f1 去Foo中找f1,打印'in Foo' 在打印 'in Info f1' 按照mro算法的执行顺序向父类中查找
class A:
def f1(self):
print('in A')
class Foo(A):
def f1(self):
super().f1()
print('in Foo')
class Bar(A):
def f1(self):
print('in Bar')
class Info(Foo,Bar):
def f1(self):
super(Foo,self).f1()
print('in Info f1')
obj = Info()
obj.f1()
1.实例化一个对象
2.先在Info 中找f1 ,执行 super(Foo,self).f1() 到Foo中找f1 在执行Foo中的super().f1() 在到Bar中找f1 打印in Foo 在打印in Info f1 按照mro算法的执行顺序向父类中查找
Info--》Foo--》Bar--》A--》object
3.严格按照对象从属于类的mro的顺序,查询下一个类.
类的成员
- 细分类的成员
class C:
name = '公有静态字段/变量'
_phone = 15032551128 #私有静态变量
def __init__(self,name):#特殊方法
self.name = name
def func(self): #普通方法
print(C.name)
def _func(self,name): #私有方法
self.name = name
print('私有方法')
class d(C):
def show(self):
print(C.name)
@classmethod
def class_func(cls):
print("类方法")
@staticmethod
def static_func():
print("静态方法")
@property
def prop(self):
print("属性")
obj = C("八戒")
print(obj.name)
print(C.nunc()
obj1 = d(1)
obj1.show()
- 类的私有成员
公有成员,在任何地方都能访问
私有成员,只有在类的内部才能方法
静态字段(静态属性)
公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
class C:
name = "公有静态字段"
def func(self):
print (C.__name)
class D(C):
def show(self):
print (C.__name)
C.name # 类访问
obj = C()
obj.func() # 类内部可以访问
obj_son = D()
obj_son.show() # 派生类中可以访问
私有静态字段:仅类内部可以访问;
class C:
__name = "私有静态字段"
def func(self):
print (C.__name)
class D(C):
def show(self):
print (C.__name)
C.__name # 不可在外部访问
obj = C()
obj.__name # 不可在外部访问
obj.func() # 类内部可以访问
obj_son = D()
obj_son.show() #不可在派生类中可以访问
***************************************************
普通字段(对象属性)
1.公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问
class C:
def __init__(self):
self.foo = "公有字段"
def func(self):
print(self.foo) # 类内部访问
class D(C):
def show(self):
print(self.foo) # 派生类中访问
obj = C()
obj.foo # 通过对象访问
obj.func() # 类内部访问
obj_son = D();
obj_son.show() # 派生类中访问
2.私有普通字段:仅类内部可以访问
class C:
def __init__(self):
self.__foo = "私有字段"
def func(self):
print(self.foo) # 类内部访问
class D(C):
def show(self):
print(self.foo) # 派生类中访问
obj = C()
obj.__foo # 通过对象访问 ==> 错误
obj.func() # 类内部访问 ==> 正确
obj_son = D()
obj_son.show() # 派生类中访问 ==> 错误
*****************************************************************************************************
类的私有成员
1.在类的内部访问
class A:
name = "liye"
__name = "gangge"
def func(self):
print(self.name) #类的内部
print(self.__name) #类的内部
obj = A()
obj.func()
类的外部不能访问私有方法
class A:
name = "liye"
__name = "gangge"
def func(self):
pass
obj = A()
print(obj.name) #liye
print(A.__name) #错误
print(obj.__name) #错误
类的派生类不能访问
class A:
name = '李业'
__name = '钢哥'
class B(A):
def func(self):
print(self.__name)
obj = B()
# print(obj.__name)
obj.func()
总结:私有对象属性只能在类的内部使用,不能再类外部以及派生类使用.
class A:
def __init__(self,name,pwd):
self.name = name
self.pwd = pwd
def md5(self):
self.__pwd = self.__pwd + "123"
obj = A("八戒",123456)
print(obj.__pwd) #'A' object has no attribute '__pwd' 错误
私有成员来说: 当你遇到重要的数据,功能,(只允许本类使用的一些方法,数据)设置成私有成员.
python所有的私有成员都是纸老虎,形同虚设.
class A:
name = '李业'
__name = '钢哥' # 私有类的属性
def __func(self):
print('in __func')
print(A.__dict__)
print(A._A__name)#别用
类从加载时,只要遇到类中的私有成员,都会在私有成员前面加上_类名 .
类的其他方法
类方法有什么用???
1. 得到类名可以实例化对象.
2. 可以操作类的属性.
class A:
def func(self):
print('实例方法')
@classmethod #类方法
def cls_func(cls):
print(f'cls---->{cls}')#<class '__main__.A'>
obj = cls()
print(obj)
print('类方法')
print(A) #<class '__main__.A'>
A.cls_func()
obj = A()
obj.cls_func()
类方法: 一般就是通过类名去调用的方法,并且自动将类名地址传给cls,
但是如果通过对象调用也可以,但是传的地址还是类名地址
创建学生类,只要实例化一个对象,写一个类方法,统计一下具体实例化多少个学生?
原则上,类方法是将类本身作为对象进行操作的方法,默认有个 cls 参数,可以被类和对象调用
通过实例化一个对象就执行一次 __init__方法 然后调用add 函数 执行自动加1
class Student:
count = 0
def __init__(self,name,id):
self.name = name
self.id = id
Student.add()
@classmethod
def add(cls):
print(cls)
cls.count+=1
@classmethod
def get(cls):
return cls.count
obj1 =Student("liye",2542621222)
obj1 =Student("liye",2542621222)
obj1 =Student("liye",2542621222)
print(obj1)
print(Student.get())
class student:
count = 0
def __init__(self,name,id):
self.name = name
self.id = id
student.add()
@classmethod
def add(cls):
cls.count += 1
return cls.count
obj = student("d",252531)
obj1 = student("d",252531)
obj2 = student("d",252531)
print(student.count)
student.add()
静态方法
class A:
def func(self):
print('实例方法')
@classmethod
def cls_func(cls):
pass
@staticmethod
def static_func():
print('静态方法')
静态方法是不依赖于对象与类的,其实静态方法就是函数.
保证代码的规范性,合理的划分.后续维护性高.
@property的组合
class Foo:
@property
def bmi(self):
print("1")
@bmi.setter
def bmi(self,v):
print(2)
@bmi.deleter
def bmi(self):
print(3)
obj = Foo()
obj.bmi #不加括号也可以直接调用bmi 函数
obj.bmi = 666 #操作命令,这个命令并不是改变bmi的值,而知执行被bmi.setter装饰器装饰的函数 得不到返回值(return)
del obj.bmi #操作命令,这个命令并不是删除bmi的值,而知执行被bmi.setter装饰器装饰的函数 得不到返回值(return)
利用实例化对象的方式设置属性.
class Foo:
def get_AAA(self):
print('get的时候运行我啊')
def set_AAA(self,value):
print('set的时候运行我啊')
def delete_AAA(self):
print('delete的时候运行我啊')
AAA = property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA
*****************************************************************************************************
isinstance(a,b):判断a是否是b类(或者b类的派生类)实例化的对象
issubclass(a,b): 判断a类是否是b类(或者b的派生类)的派生类