【python】魔术方法3

举报
子都爱学习 发表于 2021/12/20 22:29:38 2021/12/20
【摘要】 反射 概述 运行时,runtime,区别于编译时,指的是程序被加载到内存中执行的时候。 反射,reflection,指的是运行时获取类型定义信息。 一个对象能够在运行时,像照镜子一样,反射出其类型信息。 简单说,在Python中,能够通过一个对象,找出其type、class、attribute或method的能力,称为反射 或者自省。 具有反射能力的函数有 type()、isinstance...
反射
概述
运行时,runtime,区别于编译时,指的是程序被加载到内存中执行的时候。
反射,reflection,指的是运行时获取类型定义信息。
一个对象能够在运行时,像照镜子一样,反射出其类型信息。
简单说,在Python中,能够通过一个对象,找出其typeclassattributemethod的能力,称为反射
或者自省。
具有反射能力的函数有 type()isinstance()callable()dir()getattr()

建函数

getattr(object,    name[, default])

通过name返回object的属性当属性不存在将使用default返回如果没 default则抛出AttributeError  name必须为字符串

setattr(object,

name, value)

object的属性存在则覆盖不存在新增

hasattr(object, name)

判断对象是否有这个名字的属性  name必须为字符串


class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

p1 = Point(4, 5)
print(p1)
print(p1.x, p1.y)
print(getattr(p1, 'x'), getattr(p1, 'y'), getattr(p1, 'z', 100)) 
setattr(p1, 'x', 10)
setattr(Point, '__str__', lambda self: "<Point {},{}>" .format(self.x, self.y))
print(p1)

# <__main__.Point object at 0x00000160F149D180>
# 4 5
# 4 5 100
# <Point 10,5>


反射相关的魔术方法

__getattr__() 、   __setattr__() 、 __delattr__() 这三个魔术方法,分别测试这三个方法


__getattr__()

属性不存在时调用,属性的值是函数的返回值


class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __getattr__(self, item):
        print('getattr~~~')
        print(item)
        return 100

p1 = Point(4, 5)
print(p1.x)
print(p1.y)
print(p1.z)

# 4
# 5
# getattr~~~
# z
# 100

例属性查找顺序

instance.__dict__ --> instance.__class__.__dict__ --> 继承的祖先类(直到object)的__dict__ ---找不到--> 调用__getattr__()


__setattr__()

设置属性时调用,属性存在则覆盖不存在新增

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __getattr__(self, item):
        print('getattr~~~')
        print(item)
        return 100

    def __setattr__(self, key, value):
        print('setattr~~~, {}={}' .format(key, value))

p1 = Point(4, 5)
print(p1.x)
print(p1.y)
print(p1.__dict__)

# setattr~~~, x=4
# setattr~~~, y=5
# getattr~~~
# x
# 100
# getattr~~~
# y
# 100
# {}

__setattr__() 方法,可以拦截对实例属性的增加、修改操作,如果要设置生效,需要自己操作实例的 __dict__ 。


__delattr__()

通过实例删除属性,就会尝试调用该魔术方法。

class Point:
    Z = 100
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __delattr__(self, item):
        print('delattr, {}' .format(item))

p1 = Point(4, 5)
del p1.x
del p1.y
del p1.Z
print(p1.__dict__)
print(Point.__dict__)
del Point.Z
print(Point.__dict__)

# delattr, x
# delattr, y
# delattr, Z
# {'x': 4, 'y': 5}
# {'__module__': '__main__', 'Z': 100, '__init__': <function Point.__init__ at 0x0000019DB320C280>, '__delattr__': <function Point.__delattr__ at 0x0000019DB320C1F0>, '__dict__': <attribute '__dict__' of 'Point' objects>, '__weakref__': <attribute '__weakref__' of 'Point' objects>, '__doc__': None}
# {'__module__': '__main__', '__init__': <function Point.__init__ at 0x0000019DB320C280>, '__delattr__': <function Point.__delattr__ at 0x0000019DB320C1F0>, '__dict__': <attribute '__dict__' of 'Point' objects>, '__weakref__': <attribute '__weakref__' of 'Point' objects>, '__doc__': None}


__getattribute__

实例的所有的属性访问,第一个都会调用 __getattribute__ 方法,它阻止了属性的查找,该方法应该 返回(计算后的)值或者抛出一个AttributeError异常。
它的return值将作为属性查找的结果。
如果抛出AttributeError异常,则会直接调用__getattr__ 方法,因为表示属性没有找到。

class Point:
    Z = 100
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __getattr__(self, item):
        return 'missing {}' .format(item)

    def __getattribute__(self, item):
        print(item)
        #raise AttributeError('Not Found')
        #return self.__dict__[item]
        #pass
        #return object.__getattribute__(self, item)
        return super().__getattribute__(item)

p1 = Point(4, 5)
print(p1.x, p1.y)
print(Point.Z, p1.Z)
print(p1.__dict__)

# x
# y
# 4 5
# Z
# 100 100
# __dict__
# {'x': 4, 'y': 5}

__getattribute__ 方法中为了避免在该方法中无限的递归,它的实现应该永远调用基类的同名方法以 访问需要的任何属性,例如 object.__getattribute__(self, name) 。
注意,除非你明确地知道 __getattribute__ 方法用来做什么,否则不要使用它。

总结

__getattr__() 

当通过搜索实例、实例的类及祖先类查不到属性就会调用此方法

__setattr__() 

通过  . 访问实例属性进行增加修改都要调用它

__delattr__() 

当通过实例来删除属性时调用此方法

__getattribute__ 

实例所有的属性调用都从这个方法开

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。