1.面向对象不是所有情况都适用
2.面向对象编程
a. 定义类
class 类名:
def 方法(self):
pass
b. 根据类创建对象
使用对象去使用类中的方法
c. self形式参数,python内部传递
class uuu:
def p(self):
print('ppp')
def o(self):
print('oii')
def kk(self, x):
print(x)
obj = uuu()
obj.kk(66)
class uuu:
def p(self):
print(self)
def o(self):
print('oii')
def kk(self, x):
print(x)
obj = uuu()
# 类的方法里面的self形参是python默认传入的调用方法时类对象的地址
print(obj) # <__main__.uuu object at 0x104019e80>
obj.p() # <__main__.uuu object at 0x104019e80>
3. 封装
使用场景:当同一类型具有相同参数时,直接封装到对象即可;
把类当做模板,创建多个对象,封装的数据可以不一样
class uuu:
def p(self):
print(self.a)
def o(self):
print(self.a) # 方法里面输出封装的对象
def kk(self, x):
print(x)
obj = uuu()
obj.a = '这是封装演示' # 在这里封装
obj.o() # 这是封装演示
obj.p()
__init__ 构造方法
class Foo:
def __init__(self, k): # 在创建类对象obj的时候,python会先默认执行__init__方法
self.name = 'liujun' # 可以在这里封装对象
self.fa = k # 也可以在创建类对象时传入一个参数用来封装
def ke(self):
print(self.fa)
def na(self):
print(self.name)
# 上面的实例如果用这个方法封装会更方便
obj = Foo('d') # 执行Foo()时就会执行类里面的__init__,此时可以传入参数
obj.na()
__del__ 析构方法
在python解释器销毁类对象时会自动执行
__call__()
class P:
def __init__(self):
print('init')
def __call__(self, *args, **kwargs):
print('call')
o = P() # init P加括号实例化会自动执行'__init__'
o() # call 实例化的类对象再加括号会自动执行'__call__'
__ getitem__()
class P:
def __getitem__(self, item):
print(item)
o = P()
o['kkkkk'] # 如果在类对象后面加'[]'并传入参数的话,就会自动执行__getitem__
__setitem__()
class P:
def __setitem__(self, key, value):
print(key, value)
o = P()
o['kkkkk'] = 123 # 如果类对象传入键值对就会自动执行__setitem__
# kkkkk 123
__delitem__()
class P:
def __delitem__(self, key):
print(key)
o = P()
del o['lllllk'] # lllllk
class P:
xx = 'sdfe'
def __delitem__(self, key):
print(key)
obj = P()
print(P.__dict__) # 取出对象内部成员
4. 继承
派生类可以继承基类的所有方法
派生类可以继承基类的基类
补充:查找源码的过程,(self.xxxx)从底层开始找
class mo: # 基类
def chi(self):
print(self.name + ' 吃')
def he(self):
print(self.name + ' 喝')
class go(mo): # 在定义类名后面括号里写另一个类名,可以继承父类的方法 ; 派生类
def __init__(self, a):
self.name = a
def jiao(self):
print(self.name + ' 旺旺')
xx = go('liujun')
xx.chi()
xx.he()
xx.jiao()
单继承:派生类和基类里面同事存在一个方法时,优先派生类
class mo: # 基类
def chi(self):
print(self.name + ' 吃')
def he(self):
print(self.name + ' 喝')
def wan(self):
print(self.name + ' 玩')
class go(mo): # 在定义类名后面括号里写另一个类名,可以继承父类的方法 ; 派生类
def __init__(self, a):
self.name = a
def jiao(self):
print(self.name + ' 旺旺')
def wan(self):
print(self.name + ' 不玩') # 当派生类和基类里面都存在同一个方法时候,优先派生类
xx = go('liujun')
xx.chi()
xx.he()
xx.jiao()
xx.wan() # liujun 不玩
多继承:多个基类同时存在同一方法时,优先左边。派生类没有相同方法的前提下
class mo: # 基类
def chi(self):
print(self.name + ' 吃')
def he(self):
print(self.name + ' 喝')
def wan(self):
print(self.name + ' 玩')
class uo:
def pa(self):
print(self.name + ' 怕')
def wan(self):
print(self.name + ' 不玩')
class go(mo,uo): # 当多个基类里面有相同方法时,优先左边的基类。
def __init__(self, a):
self.name = a
def jiao(self):
print(self.name + ' 旺旺')
xx = go('liujun')
xx.chi()
xx.he()
xx.jiao()
xx.wan() # liujun 玩
xx.pa()
5. 多态
支持多种形态
6.继承父类的构造方法
class A:
def __init__(self):
print('A构造方法')
self.t = '动物'
class C(A):
def __init__(self):
print('C构造方法')
self.n = '猫'
super(C, self).__init__() # super可以继承父类的构造方法
# A.__init__(self) # 效果同上,但不建议用此方法
p = C()
print(p.__dict__)
'''
C构造方法
A构造方法
{'n': '猫', 't': '动物'}
'''
通过类访问有:静态字段,静态方法,类方法(特殊静态方法)
通过对象访问:普通字段,类的方法
class Pro:
con = '哈哈' # 静态字段
def __init__(self, name):
self.name = name
# 普通字段
def xx(self):
print('xx' + self.name)
print(Pro.con) # 静态字段应该直接用'类'来调用
obj = Pro('liu')
obj.xx() # 而方法应该使用'类对象指针'来调用
class Pro:
con = '哈哈' # 静态字段
def __init__(self, name):
self.name = name
# 普通字段
@staticmethod # 通过这个方法使xx变成静态方法,静态方法也不需要self做参数
def xx(): # 有需要也可以设置参数
print('xx')
Pro.xx() # 静态方法应该直接使用类去调用
class Pro:
con = '哈哈' # 静态字段
def __init__(self, name):
self.name = name
# 普通字段
@classmethod # @classmethod使xxo变成类方法
def xxo(cls): # 必须传入参数cls,就是当前类的名字,也可以自定义参数
print('xxo', cls)
Pro.xxo() # 类方法调用
# xxo <class '__main__.Pro'>
特性:为了将方法伪造成字段;就像self.name是一个普通字段,是可以直接在内存中修改值的,
class Pro:
con = '哈哈' # 静态字段
def __init__(self, name):
self.name = name
# 普通字段
@property # 特性,将方法伪造成一种字段
def xo(self):
return self.name
obj = Pro('liu')
ret = obj.xo # 在调用时不能加括号和参数,使用对象调用
print(ret)
# liu
设置特性
class Pro:
con = '哈哈' # 静态字段
def __init__(self, name):
self.name = name
# 普通字段
@property
def xo(self):
return self.name
@xo.setter # 在这里装饰一个可以设置xo的方法setter,然后就可以传入一个值给xo
def xo(self, value):
self.name = value # 在这里传进来的值把self.name改了
obj = Pro('liu')
obj.xo = '设置的值' # 原来是不可以传参数的,加了@xo.setter后,可以传入一个值
print(obj.xo)
# 设置的值
7.总结
三大特性:封装、继承、多态
成员: 字段 【静态字段(每个对象都有一份的时候用)、普通字段(每个对象都有不用数据的时候用)】
方法 【静态方法(无需使用对象封装的内容)、类方法、普通方法(使用对象中的数据)】
特性 【普通特性(将方法伪造成字段)】
快速判断,类执行,对象执行
有self:对象调用
无self:类调用
8.成员修饰符
只有内部成员才能调用;
私有的也不能继承到子类;
所有成员都一样的规则;
# 成员修饰符
class Foo:
xo = 'xo'
__ox = 'ox' # 前面加了'__'下划线的是内部成员私有的字段。在外部不能用类去调用
def f(self):
print(Foo.__ox)
def a(self):
return 'a'
print(Foo.xo)
# print(Foo.__ox) # 这里调用会出错 AttributeError: type object 'Foo' has no attribute '__ox'
obj = Foo() # 只能内部成员调用
obj.f()
# xo
# ox
class Foo:
xo = 'xo'
__ox = 'ox' # 前面加了'__'下划线的是内部成员私有的字段。在外部不能用类去调用
def __init__(self, name):
self.__name = name # 私有的普通字段
def f(self):
print(Foo.__ox)
def a(self):
print(self.__name)
obj = Foo('liu')
# print(obj.__name) # 'Foo' object has no attribute '__name' ,私有的普通字段也一样,外部不能掉用
obj.a() # liu 让内部成员调用就可以
强制访问私有对象的方法
class Foo:
xo = 'xo'
__ox = 'ox'
def __init__(self, name):
self.__name = name
obj = Foo('liu')
print(obj._Foo__ox) # 这是Python内部提供的强制访问的方法