面向对象
一、概念
-
类(class): 用来描述具有相同属性和方法的对象的集合 对象是类的实例化
-
类变量:类变量在整个实例化的对象中是共用的。定义在类中 并且是函数体外的
-
实例变量:只能作用于 当前类的实例化后的某一个对象上
-
实例: 创建一个类的具体实例 类的具体化对象
-
方法: 就是类中的函数
-
属性:就是类中的函数外的变量
二、命名方式
-
大驼峰 首字母大写
-
见名知意
-
严格区分大小写
三、类的定义
class 类名:
属性
方法
其中的属性 和方法 都是可有可无(语法上没有问题的)
四、类中的属性和方法的调用
对象 = 类名([参数])
对象.属性名
对象.方法名([参数])
五、self
self代表当前类的实例 而非类
在你实例化类的时候 会自动传入 方法需要有一个参数来去接收当前实例化后的的对象 这个self对象 就是外部实例化的那个对象
self的作用:
-
可以去创建对象属性
-
在类的内部调用属性和方法 和外部一样 对象.属性/方法名 只是里面的对象 统一叫self(别的名称也可以 不规范)
证明
class Person:
sex = '男'
def mouth(self,*args,**kwargs):
print(args,kwargs)
def test(abc):
print(abc)
p1 = Person()
p2 = Person()
print(p1)
p1.test()
print(p2)
p2.test()
print(p1.sex)
class Person:
sex = '男'
def createVar(self,var):
self.var = var
print(self.__dict__)
p = Person()
p.__dict__
p.createVar('我是实例化后的p')
__dict__ 以字典的形式 返回对象或者类中的属性和方法
六、属性和方法注意事项
属性:
当给类里面的属性 使用对象.属性名 = 值得时候 并不是将类里面得属性值进行修改 而且在当前对象里面创建了一个同名得属性 在查找得时候 会优先取当前对象查找 如果查找不到 则去类中查找 对象和类是一个引用关系 当类里面得属性发生修改 则全部对象全部对应发生改变
方法:
方法就是函数,参数和return返回值使用都一样
七、例子
class ATM:
money = 0
user = ''
def setMoney(self,money):
money = int(money)
if money>=100:
self.money += money
print('你好{} 您得余额为 {}'.format(self.user,self.money))
else:
print('请输入正确金额')
def getMoney(self,money):
money = int(money)
if money<=self.money and self.money>=100 and money>=100:
self.money -= money
print('余额为{}'.format(self.money))
else:
print('请输入正确金额')
def lookMoney(self):
print('您好{} 您得余额为{}'.format(self.user,self.money))
zhangsan = ATM()
zhangsan.user = 'zhangsan'
zhangsan.setMoney(100)
zhangsan.getMoney(100)
zhangsan.lookMoney()
lisi = ATM()
lisi.user = '李四'
lisi.setMoney(1000)
lisi.getMoney(100)
lisi.lookMoney()
八、对象属性和类属性
-
在对象中 创建了和 类中相同得属性名得时候 在调用会优先调用对象得属性
-
对象属性可以被删除 删除以后会去类中查找
-
对象属性优先级高于类属性
-
对象不可以删除或修改类里面得属性和方法你只有使用权力
-
在类中定义得属性 称之为类属性 在对象或者类中方法创建得属性 称之为对象属性
(1) 绑定对象属性的方法
实例:
class A:
x = 'x' #此刻为类属性
def createVar(self,var):
self.var = var #此属性为对象属性
a = A()
a.x = 'x' #对象属性
del a.x #此刻删除得为 对象a里面得x属性
del a.x #此刻在删除 为删除类里面得x 不允许修改
print(a.x)
(2) 绑定类属性
类名.新得属性名 = 属性值
实例
class A:
pass
a = A()
A.newAttr = '给类绑定新属性'
print(a.newAttr) #给类绑定新属性
注意:
注意绑定类属性得顺序 需要在对象实例化或者对象调用属性得上方进行绑定类属性 说白了就是 先绑定 后调用(因为加载顺序)
(3) 系统函数 对类/对象属性得操作(返回bool值)
hasattr() 判断当前对象/类是否存在某属性
setattr() 设置对象/类属性
getattr() 获取对象/类属性
实例
class A:
message = '他年方25 英年早泄'
def demo(self):
print('你是怎样调用得呢?',self)
a = A()
b = A()
#判断当前类/对象 是否存在某属性 返回布尔值
print(hasattr(a,'message')) #True
print(hasattr(A,'message')) #True
print(hasattr(a,'name')) #False
#通过函数获取属性值
print(getattr(a,'message')) #他年方25 英年早泄
print(getattr(a,'aaaa','404')) #NOT Found http状态码
setattr(a,'x','x') #给对象 a绑定对象属性x 只有当前对象a能够获取到
setattr(A,'x','x') #给类A绑定类属性以后 所有对象都能够获取到
print(a.x)
print(b.x)
九、给对象和类绑定方法
(1) 给对象绑定方法
from types import MethodType
实例
class A:
pass
from types import MethodType
def func(self):
print(self)
a = A()
b = A()
a.func = MethodType(func,a)
# print(a.__dict__) #{'func': <bound method func of <__main__.A object at 0x000001EC1DCDF1D0>>}
a.func() #只有当前对象有此方法
b.func()
只有当前对象有此方法
(2) 给类绑定方法
class A:
def demo(self):
pass
def func(self):
print('你调用我了')
A.func = func #这个操作和下面得代码是一样得
"""
a = func
print(a)
a(1)
"""
# print(A.__dict__)
a = A()
# print(a.func) #打印函数体
# print(a.demo) #打印函数体
A.func('传参')
b = A()
b.func()
所有得对象都会有类绑定得方法 (等学完继承以后 不要这么干 因为一旦改动 所有得对象 都会拥有)
十、__slots__ 限制对象属性得添加
作用: 能够对对象属性添加起到限制作用 如果添加了slots以外得属性 则抛出attributeError得异常
实例:
class A:
__slots__ = ('name','sex','age') #注意事项 只能使用括号里面得属性 系统属性也不能够使用了
十一、私有属性、私有方法
(1) 私有属性
__private_attr:俩个下划线作为开头 ,声明当前属性为私有 只有在类得内部可以使用 不能在类得外部被使用或者 直接访问 在类得内部调用为 self.__private_attr
私有属性得访问
对象/类._类名__私有属性名
其实你的私有属性在存储得时候 自动转换成了 _类名__私有属性名 所以你在调用 __私有属性名得时候 抛出属性错误得异常
注意:
虽然这样也可以访问到 但是强烈建议不要这么做 不同得版本解释器可能会将 _类名 改成不同得名字称
实例
class B:
__girlFriend = '小凤'
def YongMyself(self):
print('自己内部可以用',self.__girlFriend)
def update(self):
# self.__age = 20 #此刻在类得内部创建了一个对象私有属性 __age
self.__dict__['__age'] = 20 #获取对象中得公有属性 __age 并修改其值
zhangsan = B()
print(zhangsan.girlFriend) #AttributeError: 'A' object has no attribute 'girlFriend'
zhangsan.YongMyself() #可以通过共有得方法 获取私有属性得值 也就是私有在类得内部十可以调用得
print(B.__dict__) #查看B类中得所以属性和方法
print(zhangsan._B__girlFriend) #通过对象调用私有属性
print(B._B__girlFriend) #通过类来调用私有属性
zhangsan.__age = 18 #创建了一个名字为__age 得公有对象属性
zhangsan.update()
print(zhangsan.__age)
print(zhangsan.__dict__)
print(zhangsan._B__age)
(2) 私有方法
__private_method: 方法名以俩个下划线作为开头 声明当前方法为 私有方法 只能在类得内部调用 不能够在外部访问 在类得内部调用为 self._private__method
私有方法得访问
对象/类._类名__私有方法
其实你的私有方法在存储得时候 自动转换成了 _类名__私有方法名 所以你在调用 __私有方法名得时候 抛出属性错误得异常
实例
class A:
def __demo(self):
print('你能不能调用到我呢?')
def public_method(self): #在公有方法中 调用私有方法
self.__demo()
a = A()
a._A__demo() #私有方法得调用
A._A__demo(a)
注意:
私有属性和方法 不会被继承
十二、装饰器
可以将方法 像属性一样去调用 起到对值得过滤
-
@property 对于属性进行获取
-
@方法名.setter 对属性进行赋值/修改值
实例
class A:
sex = 'women'
__age = 20
# def age(self):
def age(self):
return self.__age
def age(self,age):
if 1<=age<=100:
self.__age = age
else:
raise ValueError
a = A()
a.age = 101
print(a.age)
十三、继承
概念: 面向对象编程 最主要得作用就是 代码得重用 实现重用得方法就是 继承机制
被继承得类 称之为 父类、基类和超类(Base class Super class)
继承得类称之为 子类
(1) 单一继承
通常一个类 如果没有继承得父类得时候 可以继承object类(它是所有类得父类)
格式
class Son(BaseClass):
pass
实例
class Demo(object):
pass
#此刻为继承所有类得超类object 不论你是否继承object 都会默认继承
class People(object):
name = ''
age = 0
__weight = 0
money = 100000
__smallThree = '小凤'
#定义一个构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("{}说 我今年{}岁了".format(self.name,self.age))
def __privateSon(self):
print('私生子 不会被继承')
class Son(People):
def smallMother(self):
# print(self.__smallThree)
# print(self._People__smallThree) #私有属性和方法 不会被继承
print(self.name)
print(self.money)
def demo(self):
# self.speak()
# self.__privateSon() #会在类中查找 但是查找得为 _Son__privateSon()
self._People__privateSon()
son = Son('张三',18,70)
print(son.name,son.money) #拥有了父类得所有公用得东西
son.smallMother()
son.demo()
注意:
-
父类得私有属性和方法 是不会被继承 但是可以通过
self.__属性名
和self._类名__方法名
去调用父类得私有属性和方法 -
当子类中存在和父类同名得方法时 会将父类得方法覆盖掉(父类方法得重写)
十四、父类方法得调用
方法1
super().方法名()
方法2
super(类名,self).方法名
方法3
类名.方法名(self)
实例
class Animal(object):
def __init__(self,name):
self.name = name
def saySomething(self):
print('我是{}'.format(self.name))
dog = Animal('dog')
class Dog(Animal):
def __init__(self,name):
super().__init__(name)
# Animal.__init__(self,name) #传入当前对象 self
# super(Dog,self).__init__(name) #单一继承得时候 不建议加参数 默认会传递 当有多继承得时候 需要使用 传递参数 因为这时候需要指定你想调用得是 哪一个父类得里面得方法
dog = Dog('dog')
dog.saySomething()
十五、多继承
主体结构
class SonClass(base1,base2...):
pass
将要多继承得类名 写入括号中,以逗号隔开 如果有重复得方法得存在 注意类得摆放顺序
实例:
#动物类
class Animal:
def animal(self):
print('属于动物类')
#跑得类
class Run(Animal):
def run(self):
print('跑的类')
#能飞得类
class Fly(Animal):
def fly(self):
print('飞的类')
#哺乳类
class Lactation(object):
def lactation(self):
print('哺乳类')
#鸟类
class Bird(object):
def bird(self):
print('鸟类')
#蝙蝠继承了哺乳类
class BianFu(Fly,Lactation):
pass
bianfu = BianFu()
bianfu.animal()
bianfu.lactation()
class Dog(Run,Lactation):
pass
dog = Dog()
dog.animal()
dog.run()
注意:
当进行多继承的时候 会将父类中所有的方法和属性 进行继承 如果存在重复的方法 且没有指定的时候 会按照进程父类的摆放顺序 从左至右依次搜索 直到搜索到指定的方法为止
多继承的父类方法的调用
class A:
def func(self):
print('我是A类的func方法')
def a(self):
print('我是A类的a方法')
class B:
def func(self):
print('我是B类的func方法')
def b(self):
print('我是B类的a方法')
class D:
def func(self):
print('我是d类的func方法')
def d(self):
print('我是d类的d方法')
class C(A,B,D):
def func(self):
# B.func(self)
#当使用super时候 没有传递参数 则按照从左至右的顺序查找
# super().func()
# super(C,self).func() #从C类开始向右查找
# super(A,self).func() #从A类开始 向右查找
super(B,self).func() #从B类开始 向右查找
c = C()
c.func()
c.d()
十六、类常用的属性
-
类名.__doc__ 类的说明
-
类名.__name__ 返回当前的类名
-
类名.__base__ 返回当前的一个父类
-
类名.__bases__ 返回当前的多个父类
-
类名.__dict__ 以字典的形式 返回当前类或者对象中的所有的信息
class A:
"""
这是当前类的说明
"""
def __init__(self):
pass
class C:
pass
class B(A,C):
pass
print(A.__doc__) #当前类的说明
print(A.__name__) #返回当前的类名
print(B.__base__) #返回当前的父类
print(B.__bases__) #返回当前的多个父类
print(B.__dict__) #返回当前B类里面的所有信息
十七、静态方法和类方法
在python的类中 存在3种方法
-
静态方法
-
类方法
-
实例方法
(1) 静态方法
被@staticmethod 装饰器修饰的称之为静态方法
可以在当前类实例化 或者没有实例化的情况下去调用
实例
class A:
def func(self):
print('func方法')
#此刻static其实就是一个普通的函数 并且不能够调用类中的属性和方法
def static(self):
# return '静态方法'
self.func()
a = A()
# a.static(a)
A.func()
(2) 类方法
被@classmethod 装饰器修饰的称之为类方法
实例
class A:
name = '张三'
def func(self):
print(self.name,self.sex,'func方法')
#可以在不进行当前类的实例化 就进行调用 (在方法的内部去实例化)
#既可以使用类去调用 也可以使用对象调用
def classMethod(cls,name,sex):
# print(cls.name)
obj = cls()
obj.name = name
obj.sex= sex
return obj
a = A()
# a.classMethod()
# print(A.name)
# print(A.classMethod('张三','男'))
A.classMethod('张三','男').func() #将类的实例化 在方法种 节省了实例 并进行对象的连贯操作
十八、类的专有方法
-
__init__
:构造方法 在生成对象时 自动调用 作为类的初始化 -
__del__
:析构方法 释放对象的时候时候 可以被del 进行触发 -
__str__
将值转换成易于人阅读的形式 -
__repr__
转换为程序员的阅读方式 -
__getattr__
当获取不存在的属性的时候被触发 -
__add__
元算符重载 在俩个对象进行相加 的时候触发 (注意 只能是俩个对象相加) -
__setitem__
按照索引赋值 -
__getitem__
按照索引取值 -
__delitem__
按照索引删除值 -
__len__
计算当前的长度
(1)__init__
和__del__
的使用
class A:
f = ''
def __init__(self,path,method="w"):
self.f = open(path,method)
def Read(self,size=1024):
return self.f.read(size)
def Write(self,con):
try:
return self.f.write(con)
except:
return False
def __del__(self):
self.f.close()
a = A('./a.txt')
a.Write('xx
')
a.Write('yy
')
del a #手动触发
r = A('./a.txt','r')
print(r.Read())
# while True:
# pass
(2) __str__
和 __repr__
的使用
str和repr 都是用来显示内容的 str面向用户 repr是面向程序员的
触发的时机是不同的
class A:
f = ''
def __init__(self):
pass
def Read(self,size=1024):
pass
def Write(self,con):
pass
def __str__(self):
return '这是一个空的类'
def __repr__(self):
return 'repr'
def __del__(self):
pass
a = A()
注意
-
str和repr如果单独出现的时候 触发机制都可以
-
如果共同存在一个类中的化
-
str
print(对象)/str(对象)
-
repr
repr(对象)/在终端下 直接输出对象
-
(3)__getattr__
当调用不存在的属性的时候被触发
class A:
f = ''
def __getattr__(self, item):
# return '{}属性不存在'.format(item)
raise AttributeError("{}属性不存在".format(item))
a = A()
a.x #会触发 getattr方法
(4) __add__
运算符重载
class A:
def __init__(self,num):
self.num = num
def __add__(self, other):
return A(self.num+other.num)
def __str__(self):
return "num = "+str(self.num)
a = A(1)
b = A(2)
print(a+b)
(5) len,setitem,getitem,delitem的操作
将类模拟成字典的操作
class MyDict:
def __init__(self,key,value):
self.Dict = {}
self.Dict[key] = value
def __setitem__(self, key, value):
self.Dict[key] = value
def __getitem__(self, item):
return self.Dict[item]
def __len__(self):
return len(self.Dict)
def __delitem__(self, key):
del self.Dict[key]
def __str__(self):
return str(self.Dict)
Dict = MyDict('a','a')
Dict['b'] = 'b'
del Dict['a']
print(Dict)
print(len(Dict))
print(Dict['b'])
print(Dict['x'])
#将值转换成平方在返回
class Indexer:
def __getitem__(self, item):
return item**2
obj = Indexer()
# print(obj[2])
for i in range(5):
print(obj[i])