python 面向对象

发布于:2023-01-04 ⋅ 阅读:(228) ⋅ 点赞:(0)

前言

终于又开始了分享,歇歇停停可算是把python面向对象这块的东西学完了,在开学之际来做个总结。确实,假期的效率是低的惊人,希望疫情结束,开学不要推迟的太久,早早相见!!!

类:具有相似功能和特性的一类事物

​ 类 一个公共模板,对象是从这个公共模板产出的

对象:类的具体体现

Student 类名具有描述性,类名首字母大写,类名不宜用_

属性(变量名) 方法(函数)

在这里插入图片描述

从类名的角度分析类

查看类中的所有的内容

  • print(Student.__dict__)  只用于获取类中的所有内容
    运行结果:
    {'__module__': '__main__', 'daily': '学习', 'examination': '考试', 'work': <function Student.work at 0x000001D580B7D0D0>, 'homework': <function Student.homework at 0x000001D580B7D160>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
    
    

万能的 .

  • 1、查看
    print(Student.daily)
    
    运行结果:
    学习
    2、增加
    Student.cloth = '校服'
    print(Student.__dict__)
    
    运行结果:
    {'__module__': '__main__', 'daily': '学习', 'examination': '考试', 'work': <function Student.work at 0x000002D7DC06D0D0>, 'homework': <function Student.homework at 0x000002D7DC06D160>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None, 'cloth': '校服'}
    3、修改
    Student.examination = '不考试'
    print(Student.examination)
    
    运行结果:
    不考试
    4、删除
    del Student.daily
    print(Student.__dict__)
    
    运行结果:
    {'__module__': '__main__', 'examination': '不考试', 'work': <function Student.work at 0x0000014E956BD0D0>, 'homework': <function Student.homework at 0x0000014E956BD160>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None, 'cloth': '校服'}
    

一般类中的属性都是通过类名.的方式去操控的

一般类中的方法(除去类方法、静态方法外)不通过类名调用

从对象的角度分析类

对象

  • 类名() 就是实例化一个对象的过程

    发生了三件事

    • 1、自动执行object类中的__new__方法,在内存中创建一个对象空间
    • 2、自动执行__init__方法,并且将对象空间传给self参数
    • 3、执行__init__方法里面的代码,给对象空间封装其属性
class Student:
    daily = '学习'
    examination = '考试'
   
    def __init__(self):
        print(self)
        print('666')   

obj = Student()
print(obj)

运行结果:
<__main__.Student object at 0x0000016297271E50>
666
<__main__.Student object at 0x0000016297271E50>
#obj传给self
#实例化对象 自动执行__init__方法

对象操作对象里面的属性

在这里插入图片描述

  • 对象查看全部属性

  • obj = Student()
    print(obj.__dict__)
    运行结果:
    {'n': 'ly', 'sex': 'male'}
    
  • 对象操作对象空间的属性

  • obj.age = '20'  #增
    del obj.age 	#删
    obj.n = 'yl'	#改
    print(obj.n)	#查
    与从类名角度分析类似
    
  • 一个类可以有多个对象

  • class Student:
        daily = '学习'
        examination = '考试'
      
        def __init__(self, n, a, s):
            self.name = n
            self.age = a
            self.sex = s
       
        def work(self, c):
            self.color = c
            print(f'{self.name}的家庭作业')
    
    liye = Student('liye', 20, 'male')
    xll = Student('xll', 19, 'female')
    print(liye.__dict__)
    print(xll.__dict__)
    运行结果:
    {'name': 'liye', 'age': 20, 'sex': 'male'}
    {'name': 'xll', 'age': 19, 'sex': 'female'}
    

对象查看类中的属性

万能的 .

print(liye.daily)
运行结果:
学习

对象只能查看类中的属性,不能修改

eg:

liye.daily = '唱歌'
此时是对对象中的属性的增加
print(liye.__dict__)
{'name': 'liye', 'age': 20, 'sex': 'male', 'daily': '唱歌'}

对象调用类中的方法

liye = Student('liye', 20, 'male')
liye.work('蓝色')
Print(liye.__dict__)
运行结果:
liye的家庭作业
{'name': 'liye', 'age': 20, 'sex': 'male', 'color': '蓝色'}

self 就是类中方法的第一个位置参数,如果通过对象执行此方法,解释器就自动的将此对象空间当作实参传给self

约定俗称:类中的方法第一个参数一般都设置为self

从空间角度研究类

添加类的对象属性

  • 类的外部

  • class A:
        address = '中国'
       
        def __init__(self, name):
            self.name = name
    
    obj = A('ly')
    respose = input('yes or no')
    if respose == 'yes':
        obj.age = 20
    print(obj.__dict__) #{'name': 'ly', 'age': 20}
    
  • 类的内部

  • class B:
        address = '陕西'
        
        def __init__(self,name):
            self.name = name 
        
        def age(self):
            if self.name == 'ly':
                self.age = 20
    
    obj1 = B('ly')
    obj1.age()
    print(obj1.__dict__) #{'name': 'ly', 'age': 20}
    

添加类的静态属性

  • 类的外部

  • A.tempar = '39'
    print(A.__dict__)
    # {'__module__': '__main__', 'address': '中国', '__init__': <function A.__init__ at 0x000002B5126BD0D0>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None, 'tempar': '39'}
    
  • 类的内部

  • class C:
        address = '西安'
       
        def __init__(self, name):
            self.name = name
       
        def add(self):
            C.tempar = '38.6'
    
    obj2 = C('ly')
    print(obj2.__dict__)  #{'name': 'ly'}
    # obj2.add()
    # C.add(111)
    C.add(obj2)
    print(obj2.__dict__)  #{'name': 'ly'}
    print(C.__dict__)
    #{'__module__': '__main__', 'address': '西安', '__init__': <function C.__init__ at 0x000002BD6A91D280>, 'add': <function C.add at 0x000002BD6A91D310>, '__dict__': <attribute '__dict__' of 'C' objects>, '__weakref__': <attribute '__weakref__' of 'C' objects>, '__doc__': None, 'tempar': '38.6'}
    

对象查找类的属性规则

  • 对象查找属性的顺序:先从对象空间找 --------> 类空间找 -------> 父类空间找 ------->…
  • 类名查找属性的顺序:先从本类空间找 --------> 父类空间找-------->…
  • 单项不可逆,类名不可能找到对象的属性,且对象不可能修改类的静态属性
  • 在这里插入图片描述

在未添加ly的mind时,若del ly.mind 报错:对象只能查看类中的属性,不可修改,在此也是查找属性的位置

对象与对象之间原则上相互独立(除去组合这种特殊关系之外)

类与类之间的关系

依赖关系(主从关系)

将一个类的类名或者对象传给另一个类的方法中

eg:在棒球运动中,有击球手,有接球手,当击球动作产生时紧接着便是接球动作的执行。比如两个类击球手类和接球手类,击球手的击球方法执行后立马执行接球手的接球方法,此动作的实现便应用了依赖关系,将接球手的对象传给击球手类的击球方法:

class Bater:
    
    def __init__(self, name):
        self.name = name
    
    def bat(self, obj):
        print(f'{self.name}击球了')
        obj.catch()

class Catcher:
    
    def __init__(self, name):
        self.name = name
    
    def catch(self):
        print(f'{self.name}接到了')

obj1 = Bater('ly')
obj2 = Catcher('yl')
obj1.bat(obj2)

运行结果:
ly击球了
yl接到了

组合关系(关联组合聚合)

将一个类的对象封装成另一个类的对象的属性

eg:以相亲为例,男女朋友的交互性,就需要拿男生的类来封装女生类的属性,以此来有联系,达到谁的男朋友是谁

class Boy:
    
    def __init__(self, name):
        self.name = name
    
    def meet(self,girl_friend = None): 
        self.girl_friend = girl_friend 
    
    def have_dinner(self):
        if self.girl_friend:
            print(f'{self.name}{self.girl_friend.age}岁大的{self.girl_friend.name}吃饭')             self.girl_friend.go_shopping(self)
        else:
            print('努力找女朋友吧')

class Girl:
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def go_shopping(self, boy_friend):
        print(f'{self.name}{boy_friend.name}一起去购物')

ly = Boy('李烨')
jt = Girl('景甜', 20)
ly.meet(jt)
ly.have_dinner()

运行结果:
李烨请20岁大的景甜吃饭
景甜和李烨一起去购物

继承关系

面向对象的三大特性:封装、继承、多态

  • 什么是继承:

    • 专业角度:B继承A类,B就叫做A的子类,派生类,A就叫做B的父类,基类,超类。B类以及B类的对象使用A类的所有的属性和方法
    • 单继承,多继承
  • 继承的优点:

    • 节省代码
    • 增强耦合性
    • 代码规范化
    • 重写父类代码
  • 单继承

    • 子类以及对象可以调用父类的属性方法

    • class Animal:
          live = '有生命的'
         
          def __init__(self, name, age, sex): 
              self.name = name 
              self.age = age
              self.sex = sex
          
          def eat(self):
              print(f'p1--->{self}')
              print('动物都需要进食')
      
      class Person(Animal):
          pass
      
      class Dog(Animal):
          def eat(self):
              print('狗狗也要生活')
              
      #从类名执行父类的属性
      print(Person.__dict__)
      print(Person.live)	#有生命的
      
      #从对象执行父类的一切
      #实例化对象一定会执行三件事,__init__
      p1 = Person('ly', 20, 'male')
      print(p1.live)	#有生命的
      p1.eat()	
      print(f'p1--->{p1}')
      '''
      p1---><__main__.Person object at 0x00000250AAA33BB0>
      动物都需要进食
      p1---><__main__.Person object at 0x00000250AAA33BB0>
      '''
      
      Dog.live = '狗生'
      print(Dog.live)	#狗生
      print(Animal.live)	#有生命的
      #注意:子类以及子类对象只能调用父类的属性以及方法,不能操作(增删改)
      
      p2 = Dog('merry', 3, 'female')
      p2.eat()
      #子类将父类的方法覆盖
      #狗狗也要生活
      
    • 对象查找顺序 从对象空间找 -----> 子类找 -----> 父类找

    • 既要执行父类方法又要执行子类方法:

    • 法一:

      class Plant:
         
          def __init__(self, name, age):
              self.name = name 
              self.age = age
      
      class Shuixian(Plant):
          
          def __init__(self, name, age, yezi):
              Plant.__init__(self, name, age)
              self.yezi = yezi
      
      obj = Shuixian('puple', 3, '双叶')
      print(obj.__dict__)
      #{'name': 'puple', 'age': 3, 'yezi': '双叶'}
      

    在这里插入图片描述

    • 法二:super

    • class Plant:
         
          def __init__(self, name, age):
              self.name = name 
              self.age = age
      
      class Shuixian(Plant):
         
          def __init__(self, name, age, yezi):
              # super(Shuixian, self).__init__(name, age)
              super().__init__(name, age)
              self.yezi = yezi
      
      obj = Shuixian('puple', 3, '双叶')
      print(obj.__dict__)
      
      #{'name': 'puple', 'age': 3, 'yezi': '双叶'}
      
  • 多继承

    • 面向对象:

    • python2.2之前:都是经典类

    • python2.2直至python2.7之间存在两种类型:经典类,新式类

      • 经典类:基类不继承object,查询规则 依靠深度优先的原则
      • 新式类:基类必须继承object,查询规则 mro算法
      • 在这里插入图片描述
    • python3x:只有新式类

      class Animal:
          def work(self):
              print('动物会吃饭')
      
      class People:
          def language(self):
              print('人类可以说话')
      
      class Mermaid(Animal,People):
          pass
      
      merry = Mermaid()
      merry.work()
      merry.language()
      #动物会吃饭
      #人类可以说话
      

    如上:美人鱼既满足人的方法也满足动物的方法,通过多继承,使子类对象可以调用两个父类的动作

    但当父类有相同的方法时,继承哪个成为了一个问题 ------ 继承顺序

    • 深度优先:一条路走到黑

    • 在这里插入图片描述

    • mro算法:

      MRO是一个有序列表L,在类被创建时就计算出来。 计算公式:

      mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )(其中Child继承自Base1, Base2)
      

      对[Base1, Base2]的操作为Merge操作,其中:

    • 表头: 列表的第一个元素

    • 表尾: 列表中表头以外的元素集合(可以为空)

    • 列表:[A, B, C]
      表头是A,表尾是[B, C]

    • Merge操作示例:

      • 如计算merge( [E,O], [C,E,F,O], [C] )
        有三个列表 :  ①      ②          ③
        
        1 merge不为空,取出第一个列表列表①的表头E,进行判断                              
           各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
        2 取出列表②的表头C,进行判断
           C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
           merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
        3 进行下一次新的merge操作 ......
        --------------------- 
        

    eg:在这里插入图片描述

mro(A) = mro(A(B,C)) = [A] + merge(mro(B), mro(C), [B,C])
mro(B) = mro(B(D,E)) = [B] + merge(mro(D), mro(E), [D,E])
	   = [B] + merge([D,O], [E,O],[D,E]  单继承:mro(D) = [D,O]
       = [B,D] + merge([O],[E,O],[E])
       = [B,D,E] + merge([O],[O])
       = [B,D,E,O]
mro(C) = mro(C(E,F)) = [C] + merge(mro(E) , mro(F), [E,F])
       = [C] + merge([E,O], [F,O], [E,F])
       = [C,E] + merge([O],[F,O],[F])
       = [C,E,F] + merge([O],[O])
       = [C,E,F,O]
mro(A) = [A] + merge([B,D,E,O], [C,E,F,O], [B,C])
       = [A,B] + merge([D,E,O], [C,E,F,O], [C])
       = [A,B,D] + merge([E,O], [C,E,F,O], [C])
       = [A,B,D,C] + merge([E,O], [E,F,O])
       = [A,B,D,C,E] + merge([O], [F,0])
       = [A,B,D,C,E,F] + merge([O], [O])
       = [A,B,D,C,E,F,O] 

print(A.mro()) 可直接查看mro排序顺序

面向对象的三大特性

继承

  • super的深入了解

    • super() 严格意义上并不是执行父类的方法

      • 单继承: super()执行父类的方法
      • 多继承:super(S,self) 严格按照self从属于的类的mro的执行顺序,执行 S类的下一位
    • class A:
      
          def f1(self):
              print('in A')   #首先输出 1
      
      class Foo(A):
         
          def f1(self):
              super(Foo, self).f1()   #Foo 的下一类 Bar
              print('in Foo')         # 3
      
      class Bar(A):
          
          def f1(self):
              super(Bar, self).f1()   #Bar 的下一类 A
              print('in bar')         # 2
      
      class Info(Foo,Bar):
          
          def f1(self):
              super(Info, self).f1()  # Info 的下一类 Foo
              print('in Info')        # 4
      
      obj = Info()
      print(Info.mro())# [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]
      obj.f1()
      运行结果:
      '''
      in A
      in bar
      in Foo
      in Info
      '''
      

封装

将一些东西内容封装到一个地方,还可以取出

类设置静态属性,设置一些方法…

eg:name,age被封装,以.的方式取出

class Person:
    
    class_name = '20060317'
    
    def __init__(self,name,age):
        self.name = name 
        self.age = age
        
ly = Person('刘烨', 20)
print(ly.age)
print(ly.name)

多态

一个事物有多种形态,python中默认支持多态

eg:弱类型语言python 与 强类型语言对变量的定义

  • python:

    • name = 111
      name ='dwaf'
      name = [1, 2, 3]
      
  • c语言:

    • string name = 'ly'	
      int age = 2
      

鸭子类型:你看起来像鸭子,那么你就是鸭子

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')

如上:A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。

​ 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。

鸭子类型的应用:

例如不同数据类型list, tuple等的find, index 方法,两个类型没有耦合性,但对相同的功能设定了相同的名字,达到相同功能使用方便

定义类似如下:
class List:
    
    def find(self):
        pass
    def index(self):
        pass

class Tuple:
    
    def find(self):
        pass
    def index(self):
        pass
应用示例:
lis = [1, 2, 3]
print(lis.index(2))	#1
tu = (1, 2, 3)
print(tu.index(2))	#1

类的约束

类的约束的两种解决方法:

在父类建立一种约束

在父类定义一个pay方法,主动抛出异常,如果子类没有定义pay方法,并且沿用了父类的pay方法,就会报错

python推荐的一种约束方式

class Payment:
    def pay(self, money):
        raise Exception('子类必须定义此方法')

class QQpay(Payment):
    def pay(self, money):
        print(f'利用QQ支付了{money}')

class Alipay(Payment):
    def pay(self, money):
        print(f'利用支付宝支付了{money}')

class Wechat(Payment):
    # def pay(self, money):
    def fuqian(self, money): 
        print(f'利用微信支付了{money}')
def pay(object, money):
    object.pay(money)
obj = Wechat()
pay(obj, 100)

'''
运行结果:
Exception: 子类必须定义此方法
'''

模拟抽象类(指定一种规范)的概念,建立一种约束

固定方法:

from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):
    # 抽象类 接口类  规范和约束  metaclass指定的是一个元类
    @abstractmethod
    def pay(self):pass  # 抽象方法

基类如上设置,子类如果没有定义pay方法,在实例化对象时就会报错

eg:

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 Alipay(Payment):
    def pay(self, money):
        print(f'利用支付宝支付了{money}')

class Wechat(Payment):
    def fuqian(self, money):
        print(f'利用微信支付了{money}')

def pay(object, money):
    object.pay(money)
obj = Wechat()
'''
TypeError: Can't instantiate abstract class Wechat with abstract method pay
'''

类的成员

细分

class A:
	company_name = '华为'  # 静态变量(静态字段)
	__iphone = '0913xxxx'  # 私有静态变量(私有静态字段) 带双下划线
    def __init__(self,name,age): #特殊方法

        self.name = name  #对象属性(普通字段)
        self.__age = age  # 私有对象属性(私有普通字段)

    def func1(self):  # 普通方法
        pass

    def __func(self): #私有方法
        print(666)

    @classmethod  # 类方法
    def class_func(cls):
        """ 定义类方法,至少有一个cls参数 """
        print('类方法')

    @staticmethod  #静态方法
    def static_func():
        """ 定义静态方法 ,无默认参数"""
        print('静态方法')

    @property  # 属性
    def prop(self):
        pass

类的私有成员

只能在类的内部调用

私有成员来说:当你遇到重要的数据,功能,(只允许本类使用的一些方法,数据)设置成私有成员

  • 私有类的静态属性

  • #     在类的内部可以访问
    class A:
        name = 'ly'
        __name = 'yll'
    
        def func(self):
            print(self.name)
            print(self.__name)
    
    obj = A()
    obj.func()
    '''
    ly
    yll
    '''
    # 类的外部不能访问
    print(obj.name)
    # ly
    '''
    print(obj.__name)
    'A' object has no attribute '__name'
    '''
    # 类的派生类不能访问
    
    class B(A):
        pass
    
    objx = B()
    '''
    print(B.__name)
    type object 'B' has no attribute '__name'
    '''
    
  • 私有类的方法

  • class A:
    
        def __func(self):
            print('in A __func')
    
        def func(self):
            self.__func()
            print('in A func')
    
    objf = A()
    objf.func()
    
    '''
    in A __func
    in A func
    '''
    
    '''
    objf.__func()
    'A' object has no attribute '__func'
    '''
    
    
  • 私有对象的属性

  • class A:
    
        def __init__(self, name, pwd):
            self.name = name
            self.__pwd = pwd
    
        def change_pwd(self):
            self.__pwd = '123'
    
    objd = A('ly', '12431')
    objd.change_pwd()
    '''
    print(objd.__pwd)
    'A' object has no attribute '__pwd'
    '''
    

python所有的私有成员都是"纸老虎",形同虚设

类从加载中,只要遇到类中的私有成员,都会在私有成员前面加上 _类名

class B:
    name = 'liu'
    __name = 'liuy'
    
    def __func(self):
        print('111')

print(B.__dict__)
obj = B()
print(obj._B__name)
obj._B__func()
'''
liuy
111
'''

在这里插入图片描述

类方法

一般就是通过类名去调用的方法, 并且自动将类名地址传递给cls,

但是如果通过对象调用也可以,传的地址仍然是类名地址

class C:

    def func(self):
        print('实例方法')

    @classmethod
    def cls_func(cls):
        print(f'cls -> {cls}')
        print('类方法')

print(C)
C.cls_func()
'''
<class '__main__.C'>
cls -> <class '__main__.C'>
类方法
'''
obj = C()
obj.cls_func()
'''
cls -> <class '__main__.C'>
类方法
'''

对于面向对象的编程,类方法的作用表现在:

  • 得到类名可以实例化对象
  • 可以操作类的属性

eg:

#创建学生类,只要实例化一个对象,写一个类方法,统计一下具体实例化对象的个数

class Student:
    count = 0

    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.total()


    @classmethod
    def total(cls):
        cls.count = cls.count + 1

    @classmethod
    def num(cls):
        return cls.count

p1 = Student('ly', 20)
p2 = Student('ly', 20)
p3 = Student('ly', 20)
p4 = Student('ly', 20)
p5 = Student('ly', 20)
print(Student.num())
# 5

静态方法

不依赖于对象与类,其实静态方法就是函数

但依靠类名,对象调用

class D:
    def func(self):
        print('实例方法')
    
    @staticmethod
    def static_func():
        print('静态方法')

D.static_func()
c = D()
c.static_func()
'''
静态方法
静态方法
'''

类似于:
def static_func():
    print('静态方法')
static_func()

保证代码的规范性,合理划分,以及后续的维护性

eg:静态方法不依赖于对象与类,但属于时间大类的功能,合理划分

class Time:

    def __init__(self, hour, minute, second):
        self.hour = hour
        self.minute = minute
        self.second = second

    def change_time(self):
        print(f'你修改的时间为{self.hour}:{self.minute}:{self.second}')

    @staticmethod
    def now_time():
        import time
        print(time.strftime('%H:%M:%S'))

x = Time('11', '5', '21')
x.change_time()
x.now_time()

属性

  • property 将执行一个函数需要函数名() 变换为直接函数名

    将动态方法伪装成一个属性,虽然在代码级别上没有什么提升,但是让你看起来更合理

  • eg:BMI系数对于人们来说应该是属性一样的东西,并非一种方法,通过@property将方法伪装成属性

  • class Person:
        def __init__(self, name, weigth, height): 
            self.name = name
            self.weight = weight
            self.height = height
        @property
        def bim(self):
            return self.weight / self.height ** 2
    ly = Person('ly', 70, 1.72)
    print(ly.bim)
    
  • property是一个组合

    由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除

设置属性的两种方式

1、利用装饰器

  • class Foo:
    
        @property
        def ABC(self):
            print('get的时候运行我')
    
        @ABC.setter
        def ABC(self, value):
            print(value)
            print('set的时候运行我')
    
        @ABC.deleter
        def ABC(self):
         print('delete的时候运行我')
    
    obj = Foo()
    obj.ABC
    # get的时候运行我
    obj.ABC = 666
    '''
    666
    set的时候运行我
    '''
    del obj.ABC
    # delete的时候运行我
    

2、利用实例化对象的方式

  • 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
    # get的时候运行我
    f1.AAA = 'aaa'
    # set的时候运行我
    del f1.AAA
    # delete的时候运行我
    

应用场景:一些方法名类似于属性,可以让其伪装为属性

isinstance issubclass

  • isinstance 判断的是对象与类的关系 isinstance(a,b) a是否是b类或者b类派生类实例化的对象
class A:
    pass

class B(A):
    pass

obj = B()

print(isinstance(obj, A))
print(isinstance(obj, B))
'''
True
True
'''
  • issubclass 判断的是类与类之间的关系 issubclass(a,b) a类是否是b类 子孙类
class A:
    pass

class B(A):
    pass

class C(B):
    pass

print(issubclass(B, A))
print(issubclass(C, A))
'''
True
True
'''

type元类

  • type不仅可以查看数据的类型,也可以获取对象所从属于的类

  • print(type("dwafaf"))
    print(type(list))
    print(type(tuple))
    print(type(str))
    '''
    <class 'str'>
    <class 'type'>
    <class 'type'>
    <class 'type'>
    '''
    
  • python中一切皆对象,类在某种意义上也是一个对象,python中自己定义的类以及大部分内置类,都是由type元类(构建类)实例化得来的

  • type与object的关系

    • object类是type类的一个实例

    • print(type(object))
      # <class 'type'>
      
    • object类是type类的父类

    • print(issubclass(type, object))
      # True
      

反射

程序对自己内部的一种自省方式

  • 反射:通过字符串操作对象的方式

    • 应用于:

      实例对象

      本模块

      其他模块

    hasattr getattr setattr delattr

实例对象

class Person:
    country = 'China'

    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def func(self):
        print('in Person func')


obj = Person('ly', 20)
  • hasattr:检测是否含有某属性

  • print(hasattr(obj, 'name'))
    print(hasattr(obj, 'age'))
    print(hasattr(obj, 'country'))
    '''
    True
    True
    True
    '''
    
  • getattr:获取属性

  • print(getattr(obj, 'name'))
    f = getattr(obj, 'func')
    f()
    '''
    ly
    in Person func
    '''
    当属性不存在时,可添加参数设置返回值,不让报错
    print(getattr(obj, 'sex', None))
    # None
    一般组合使用
    if hasattr(obj, 'name')
    	getattr(obj, 'name')
    
  • setattr:设置属性

  • setattr(obj, 'sex', '男')
    print(obj.sex)
    # 男
    
  • delattr:删除属性

  • delattr(obj, 'sex')
    print(obj.sex)
    # 'Person' object has no attribute 'sex'
    

类的角度

class Person:
    country = 'China'

def __init__(self, name, age):
    self.name = name
    self.age = age
    
def func(self):
    print('in Person func')
  • hasattr与getattr

  • if hasattr(Person, 'func'):
        obj = Person('ly', 20)
        getattr(Person, 'func')(obj)
        
    # in Person func
    

从本模块

import sys

sys.modules[__name__] 为本模块

a = 666

def func():
    print('in 本模块')
    
import sys

print(getattr(sys.modules[__name__], 'a'))

if hasattr(sys.modules[__name__], 'func'):
    getattr(sys.modules[__name__], 'func')()''
666
in 本模块
'''  

从其他模块

  • 模块xll内容

  • name = 'ly'
    
    def func():
        print('in xll')
    
    class C:
        def __init__(self, name, age):
            self.name = name
            self.age =age
    
  • 执行文件

  • import xll
    print(getattr(xll, 'name'))
    
    if hasattr(xll, 'func'):
        getattr(xll, 'func')()
        
    '''
    ly
    in xll
    '''
    

函数与方法的区别

通过打印函数名的方法区别

def func1():
    pass
class A:
    def func(self):
        pass

# 1、通过打印函数名的方法区别什么是方法,什么是函数
print(func1)
print(A.func) #通过类名调用的类中的实例方法叫做函数
'''
<function func1 at 0x00000245A5F7D040>
<function A.func at 0x00000245A5F7D160>  
'''
obj = A()
print(obj.func) # 通过对象调用的类中的实例方法叫方法
# <bound method A.func of <__main__.A object at 0x00000245A5CC97C0>>

借助模块判断

from types import FunctionType
from types import MethodType

def func():
    pass


class A:
    def func(self):
        pass

objx = A()

print(isinstance(func, FunctionType))
print(isinstance(A.func, FunctionType))
print(isinstance(obj.func, FunctionType))
print(isinstance(obj.func, MethodType))
'''
True
True
False
True
'''

总结:函数都是显性传参,方法都是隐性传参

  • python中一切皆方法,类在某种意义上也是一个对象,python中自己定义的类,以及大部分内置类,都是由type元类(构建类)实例化得来的

  • python中一切皆对象,函数在某种意义上也是一个对象,函数这个对象是从FunctionType这个类实例化得来的

  • python中一切皆对象,方法在某种意义上也是一个对象,方法这个对象是从MethodType这个类实例化得来的

其它语言中:java中只有方法 c中只有函数 c++ 类中:方法 类外:函数

双下方法

双下方法的内容确实也是比较多的,我们就放在下一篇内容分享吧,开学快乐!!!

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到