千锋教育-做有情怀、有良心、有品质的职业教育机构

400-811-9990
手机站
千锋教育

千锋学习站 | 随时随地免费学

千锋教育

扫一扫进入千锋手机站

领取全套视频
千锋教育

关注千锋学习站小程序
随时随地免费学习课程

上海
  • 北京
  • 郑州
  • 武汉
  • 成都
  • 西安
  • 沈阳
  • 广州
  • 南京
  • 深圳
  • 大连
  • 青岛
  • 杭州
  • 重庆
当前位置:成都千锋IT培训  >  技术干货  >  Python对象的方法调用时发生了什么?

Python对象的方法调用时发生了什么?

来源:千锋教育
发布人:xqq
时间: 2023-10-17 14:10:23

一、Python对象的方法调用时发生了什么

1.寻找Eat

catObj寻找一个叫Eat的东西,这东西可能是任意对象,名字就叫Eat(暂且先忘了Cat类里定义了什么),这其实就涉及到Python属性访问顺序了:

__getattribute__数据描述符对象属性类属性非数据描述符父类属性__getattr__()

为了更简单得去理解,本文只关注对象属性,类属性,父类属性这三点。

首先从对象属性去找:

catObj对象有没有名为Eat这个属性?从上面定义的Cat类看显然是没有,这个对象只有一个属性name,可打印__dict__查看对象的属性。

print(catObj.__dict__)

# 打印结果:

# {‘name’: ‘Godeng’}

catObj.food = “Fish”

# 打印结果:

# {‘name’: ‘Godeng’, ‘food’: ‘Fish’}

对象添加一个属性,它就会进对象的__dict__里,归根结底都是字典访问。

对象属性找不到,去类属性找,从catObj对象的__class__属性即可索引到类:

Cat类有没有名为Eat这个属性?从上面定义的Cat类看,显然是有的,且类也是对象,也可通过打印__dict__观察它的属性。

print(Cat.__dict__)

# 打印结果:

# {…’Eat’: ,

# ‘__init__’: …}

Eat和__init__赫然在列,而且Eat和__init__是一个质朴得不能再质朴的函数,函数,函数。

如果在类属性找不到的话,就会尝试去父类属性寻找,相似的过程。

那么到此,寻找到了一个名为Eat的函数。

2.包装成Eat方法&调用

def Eat(self):

    print(“Cat is eating”)

从catObj对象一路寻找到的Eat函数是长这样的,但它并非最终的返回的方法。将函数与对象进行包装后的产物,才是方法。

class Method(object):

    def __init__(self, obj, func):

       self.__self__ = obj

       self.__func__ = func

    def __call__(self, *args, **kwargs):

       self.__func__(self.__self__, *args, **kwargs)

catObj = Cat(“Godeng”)

eatMethod = Method(catObj, Cat.Eat)

eatMethod()

上面是模拟方法的结构和大致产生调用过程,方法对象自身会引用Cat类函数Eat,和eatObj对象,并方法对象被调用时(__call__调用时),自动把eatObj对象作为了该函数的self参数。

并非方法本身蕴含了什么不可告人的魔力,catObj.eat获取的其实就是类似上例的Method对象,从使用形式来看它提供的一个显著特点是,他就像一个不需要传self参数的函数。

方法&类函数引用上的区别:

类函数Cat.Eat是一个普通函数对象,它被Cat类引用。

catObj.Eat是一个方法对象,它引用了类函数Cat.Eat和catObj对象,它并不是像类函数那样有被Cat类或catObj对象引用的一个恒久的对象,每次catObj.Eat的调用都会走一遍上述流程,产生一个新的方法对象返回。

# 生成了一个新的方法对象,这句执行完毕后方法对象会被销毁

catObj.Eat()

# 生成了一个新的方法对象, 并由eatMethod引用,方法对象不会被销毁

eatMethod = catObj.Eat

# 删除eatMethod的引用,方法对象随之被销毁

eatMethod = None

延伸阅读:

二、如何从父类们找类函数

Python是门多继承语言,在上面catObj寻找Eat到它的类的时候,如果Cat类没有定义Eat,会尝试向父类寻找Eat。

class Monster(object):

    def Eat(self):

       print(“Monster Eat”)

class Pet(object):

    def Eat(self):

       print(“Pet Eat”)

class Cat(Pet, Monster):

    def __init__(self, name):

       self.name = name

假如Cat没定义Eat,它的两个父类Pet和Monster的都定义了Eat,那就是先在哪个父类找到Eat,那么就返回哪个父类的Eat,也即是取决于先从Pet类找,还是先从Monster类找。

这就涉及到Python一个老生常谈的概念,方法解析顺序(mro),它确定了这个顺序,它的具体规则会随着Python版本迭代而迭代,如Py2是深度优先和Py3是广度优先,具体在此就不展开了。

可通过打印类的mro来观察类的执行顺序。

print(Cat.mro())

print(Cat.Eat)

# 打印结果:

# [, , , ]

#

声明:本站稿件版权均属千锋教育所有,未经许可不得擅自转载。

猜你喜欢LIKE

sql server2012r2所在服务器做端口限制,需要开放什么端口才能继续访问数据库?

2023-10-17

Oracle有什么优势和劣势?

2023-10-17

CSS 隐藏页面元素有哪些方法?

2023-10-17

最新文章NEW

数据库聚集索引非聚集索引实现上有哪些区别?

2023-10-17

开发web应用,好的开发流程是怎么样的?

2023-10-17

为什么说Gradle是Android进阶绕不去的坎?

2023-10-17

相关推荐HOT

更多>>

快速通道 更多>>

最新开班信息 更多>>

网友热搜 更多>>