- 面向对象(属性与方法)去进行编码的过程
### 面向过程VS面向对象
- 编程思想不同:
- 面向过程:是一种以过程为中心的编程思想
- 面向对象:是一类以对象为核心的编程思想
- 特点不同:
- 面向过程:主要分析出解决问题所需要的步骤,用函数把这些步骤一步步实现,使用的十九一个个依次调用即可
- 面向对象:主要找出问题中的共性问题,作为对象进行操作
### 面向对象中常用的术语:
- 类:可以理解为一个模板,通过它可以创建出无数个具体实例
- 对象:类不能直接使用,需要通过类实例化(类的实例又称对象)之后才能使用
- 属性:类中所有的变量称为属性
- 方法:类所拥有的函数通常称为方法:方法可以分为类方法(@classmethod 修饰的方法)
- 静态方法(@staticmethod修饰的方法)和实例方法。类中定义的方法默认是实例方法,实例方法至少要包含一个self参数,只能和类的对象一起使用
- 面向对象最重要的概念就是类和实例,牢记类是抽象的模板,而实例是根据类创建出来的一个个具体的对象,每个对象都拥有相同的方法。
- class首字母大写 class Name(object):
- 类的参数self
- self 是类函数中的必传参数,且必须放在第一个参数位置
- self 是一个对象,他代表实例化的变量自身
- self 可以直接通过点来定义一个类变量 self.name = 'mark'
- self中的变量与含有self参数的函数可以在类中的任何一个函数内随意调用
- 非函数中定义的变量在定义的时候不用self
def sleep3(name): return name+'3' class Person(object): name = None age = None def run(self): print(f'{self.name} 在奔跑') def jump(self): print(f'{self.name} 在跳跃') def work(self): self.run() self.jump() def sleep2(name): # 函数中定义新的函数 return name result = sleep2(self.name) print('sleep2 result is ',result) r3 = sleep3(self.name) # 调用全局函数sleep3 print(r3) def sleep(): # 类中self是必传参数,否则无法调用 print('sleep') mark = Person() mark.run() mark.name = 'mark' mark.run() lily = Person() lily.run() lily.name = 'lily' lily.run() lily.top = 163 print(lily.top) # print(mark.top)#报错 top是属于lily这个对象新加的属性 print('========') lily.work() # lily.sleep() # 报错,无法调用 print('-------') print(sleep3('lily'))
- python中self代表类的实例:self在定义类的方法时是必须有的,虽然在调用的时候不必传入对应的参数
- python中只有针对类来说self才有意义,python中所说的self,就是指类中的self
- self只能再python类的方法中使用
- 属性:
- (1)如果变量定义在类下面而不是类的方法下面,那这个变量即是类的属性也是类实例的属性。
- (2)如果变量定义在类的方法下面,如果加了self,那这个变量就是类实例的属性,不是类的属性;如果没加self,这个变量只是这个方法的局部变量,既不是类的属性也不是类实例的属性。
- 方法:
- (1)如果在类中定义函数时加了self,那这个函数就是类实例的方法,而不是类的方法。
- (2)如果在类中定义函数时没有加self,那这个函数就只是类的方法,而不是类实例的方法。
class Dog: # 定义在类的下面,而不是类的方法下面,那这个变量即是类的属性也是类实例的属性。 color = 'yellow' name = 'lucy' # 如果变量定义在类的方法下面,如果加了self,那这个变量就是类实例的属性,不是类的属性; # 如果没加self,这个变量只是这个方法的局部变量,既不是类的属性也不是类实例的属性。 def __init__(self): self.a = 13 b = 6 print(b) # (1)如果在类中定义函数时加了self,那这个函数就是类实例的方法,而不是类的方法。 # (2)如果在类中定义函数时没有加self,那这个函数就只是类的方法,而不是类实例的方法。 def eat1(): print('类的方法') def eat2(self): print('类实例的方法') print(Dog.color) duoduo = Dog() print(duoduo.color) # print(Dog.a) # 报错,找不到类属性a print(duoduo.a) # 输出13 # print(duoduo.b) # 报错,找不到类实例属性b Dog.eat1() # Dog.eat2() # 报错,不能调用,需要传参 # duoduo.eat1() # 报错,不能调用 duoduo.eat2()
构造函数:
class Person(object): def __init__(self,name,age=None): self.name = name self.age = age def run(self): print(f'{self.name} 在奔跑') def jump(self): print(f'{self.name} 在跳跃') def work(self): self.run() self.jump() print(f'{self.name} 的年龄是 {self.age}') mark = Person(name='mark') mark.work() print('========') mark.name = 'mark.li' # 能正常修改 mark.work() print('-------') luck = Person(name='luck',age=16) luck.work()
- 对象的生命周期,python中会自动管理内存周期
- 实例化__init__:对象的生命周期开始(内存中分配一个内存块)
- __del__:删除对象(从内存中释放这个内存块)
私有函数和私有变量
- 无法被实例化后的对象调用的类中的函数与变量
- 类内部可以调用私有函数与变量
- 只希望类内部业务调用,不希望被使用者调用
- 私有变量私有函数:变量或者函数前添加__(2个下划线) (补充说明:前后都有的是内置函数)
class Dog(object): __dog_type = 'dog' def __init__(self,name,age=None): self.name = name self.__age = age def run(self): result = self.__run() print(result) def __run(self): return f'{self.__dog_type} {self.name} 在奔跑' def jump(self): result = self.__jump() print(result) def __jump(self): return f'{self.__dog_type} {self.name} 在跳跃' def work(self): self.run() self.jump() print(f'{self.name} 的年龄是 {self.__age}') mark = Dog(name='mark',age=4) mark.work() print(dir(Dog)) re = mark._Dog__jump() print(re) # print(mark.__dog_type)# 类外不能调用私有属性 print(mark._Dog__dog_type)
- python中的装饰器
- 是一种函数,可以接受函数作为参数,可以返回函数
- 接收一个函数,内部对其处理,然后返回一个新的函数,动态增强函数功能
- 列子:a函数是装饰器,将c函数作为参数传入给a函数,在a函数中可以选择执行或者不执行c函数,也可以选择对c函数的结果进行二次加工处理
- def out(func_args):外围函数 (传入需要处理的函数)
- def inter(*args,**kwargs): 内嵌函数 (因为不知道传入的func_args传入的是什么参数,所以选择可变参数)
- return func_args(*args,**kwargs) (业务逻辑代码)
- return inter (必须的一步,外围函数返回内嵌函数:所有业务逻辑都在内嵌函数中,不返回内嵌函数,就无法调用)
- 装饰器的用法:方法一:将被调用的函数,直接作为参数传入装饰器的外围函数
- 方法二:使用@符号,将装饰器与被调用函数绑定在一起,@+装饰器函数,放在被调用的函数的上一行,被调用函数正常定义,只需要直接调用被执行函数即可
def check_str(func): print('func',func) def inner(*args,**kwargs): result = func(*args,**kwargs) print('args',args,kwargs) if result == True: return '%s 验证 通过'% result else: return '%s 验证 不通过'% result return inner @check_str def test(data): if len(data) >= 3: return True else: return False result = test('ok') print(result) result = test(data='okk') print(result)
- 类的常用装饰器:classmethod;staticmethod; property
- classmethod—将类函数,可以不经过实例化而直接被调用
- staticmethod—将类函数可以不经过实例化而直接被调用,被该装饰器调用的函数不许传递self或cls参数,且无法再该函数内调用其他类函数或变量
- property—将类函数的执行免去括弧,类似于调用属性(变量)一样
class Test(object): def __init__(self,a): self.a = a def run(self): print('run') self.jump() #正常调用 self.sleep() @classmethod def jump(cls): print('jump') # cls.run() #不能调用,仍然报错 @staticmethod def sleep(): print('I want sleep') t = Test('a') t.run() # Test.run() # TypeError: run() missing 1 required positional argument: 'self## ' Test.jump() print('======') t.jump() Test.sleep() t.sleep() print('------') t.run() class Test1(object): def __init__(self,name): self.__name = name @property def name(self): return self.__name @name.setter def name(self,value): self.__name =value t1 = Test1(name='mark') print(t1.name) t1.name = 'mark.li' print('----',t1.name)
输出:
run
jump
I want sleep
jump
======
jump
I want sleep
I want sleep
------
run
jump
I want sleep
mark
---- mark.li
- 类的继承:通过继承基类来得到基类的功能,被继承的类称作父类或基类,继承者称为子类
- 代码的复用:子类拥有父类所有的属性和方法,父类不具备子类自有的属性和方法
class Parent(object): def __init__(self,name,sex): self.name = name self.sex = sex def walk(self): return f'{self.name} can walk' def is_sex(self): if self.sex == 'boy': return f'{self.name} is a boy' else: return f'{self.name} is a girl' class ChildOne(Parent): def play_football(self): return f'{self.name} play football very well' class ChildTwo(Parent): def play_piano(self): return f'{self.name} play piano very well' c_one = ChildOne(name='mark',sex='boy') re = c_one.play_football() print(re) re = c_one.is_sex() print(re) c_two = ChildTwo(name='lucy',sex='girl') re = c_two.play_piano() print(re) re = c_two.walk() print(re) print('======') p = Parent(name='Lcuk',sex='boy') pre = p.walk()# 只能调用自己的,不能调用子类的 print(pre)
- 类的多态实现:子类中重写父类的方法
class Father(object): def talk(self): print('father is talking') def jump(self): print('具有jump功能') class Brothor(Father): def run(self): print('brother is running') def talk(self): print('brother is talking') class Mark(Father): def talk(self): print('mark is talking') if __name__=='__main__': br = Brothor() br.run() br.talk() br.jump() fa = Father() fa.talk() ma = Mark() ma.talk()
class Parent(): def __init__(self,p): print('hello I am parent %s'% p) class Child(Parent): def __init__(self,c): # def __init__(self, c,p): print('hello I am child %s'% c) # super(当前类,类的实例).父类方法,python3中可以不用传 # super(Child,self).__init__(p) super().__init__(p='luck') if __name__ == '__main__': mark = Child(c='mark') # mark = Child(c='mark',p='luck')
- 类的多重继承:可以继承多个父类(基类)
- class Child(Parent1,Parent2,Parent3...) 逗号隔开,从左向右一次继承
class Tool(object): def work(self): print('tool work') def knife(self): print('Use a knife to cut fruit') class Food(object): def work(self): print('Food work') def fruit(self): print('I like fruit') class Person(Food,Tool): def __init__(self,name): self.name = name print(f'hello , I am {self.name}') if __name__ == '__main__': mark = Person(name='mark') mark.fruit() mark.knife() mark.work() print(Person.__mro__)#可以查看继承顺序
- 类的高级函数 __str__ __getattr__ __setattr__ __call__
- __str__ 功能:如果定义了该函数,当print当前实例化对象的时候,会返回该函数的return信息
- __getattr__ 当调用的属性或者方法不存在时,会返回该方法定义的信息
- __setattr__ 拦截当前类中不存在的属性和值,并设置,__setattr__(self, key, value)
- __call__ 本质是将一个实例化的类变成一个函数
class Test(object): pass class Test1(object): def __str__(self): return 'this is a test class(这是一个描述信息)' def __getattr__(self, key):# 当调用的属性或者方法不存在时,会返回该方法定义的信息 return f' key:{key} 不存在' def __setattr__(self,key,value): # 处理当前类中不存在的属性和值 print(key,value) print(self.__dict__)# 每一个类中都有一个这样的内置字典函数 # if key not in self.__dict__: self.__dict__[key] = value print(self.__dict__) def __call__(self, *args, **kwargs):#将一个实例化的类变成一个函数 print('call func ',args,kwargs) if __name__ == '__main__': t = Test() print(t) # print(t.a) # 报错'Test' object has no attribute 'a' t1 = Test1() print(t1) print(t1.a) print(t1.hy) t1.name = 'LUCK' print(t1.name) t1('nancy') t1(name='xiaoyun') # t1.a.b.c 链式操作 class Test2(object): def __init__(self,attr=''): self.__attr = attr # def __call__(self, *args, **kwargs): # print('call-func: key is %s'%self.__attr) def __call__(self,name): print('call-func2: key is %s'% name) # def __call__(self): # print('call-func-test') def __getattr__(self, key): if self.__attr: key = '{}.{}'.format(self.__attr,key) else: key = key print(key) return Test2(key) # 通过类函数调用类对象,()再次完成一次实例化,类似于递归 t2 = Test2() t2.a.b.c.d # 调用的__getattr__函数 # t2.a.b.c() # 调用的__call__函数,并且可以传参 t2.a.b.c('niuniu') t2.name.sex.age(18)