python 中__setattr__, __getattr__,__getattribute__, __call__使用方法

栏目: Python · 发布时间: 8年前

内容简介:python 中__setattr__, __getattr__,__getattribute__, __call__使用方法

object._getattr_(self, name)

拦截点号运算。当对未定义的属性名称和实例进行点号运算时,就会用属性名作为字符串调用这个方法。如果继承树可以找到该属性,则不调用此方法

实例 instance 通过 instance.name 访问属性 name 只有当属性 name 没有在实例的 __dict__ 或它构造类的 __dict__ 或基类的 __dict__ 中没有找到,才会调用 __getattr__ 。当属性 name 可以通过正常机制追溯到时, __getattr__ 是不会被调用的。 如果在 __getattr__(self, attr) 存在通过 self.attr 访问属性,会出现无限递归错误。

class ClassA(object):

    def __init__(self, classname):
        self.classname = classname

    def __getattr__(self, attr):
        return('invoke __getattr__', attr)

insA = ClassA('ClassA')
print(insA.__dict__) # 实例insA已经有classname属性了
# {'classname': 'ClassA'}

print(insA.classname) # 不会调用__getattr__
# ClassA

print(insA.grade) # grade属性没有找到,调用__getattr__
# ('invoke __getattr__', 'grade')

object.__getattribute__(self, name)

实例 instance 通过 instance.name 访问属性 name__getattribute__ 方法一直会被调用,无论属性 name 是否追溯到。 如果类还定义了 __getattr__ 方法,除非通过 __getattribute__ 显式的调用它,或者 __getattribute__ 方法出现 AttributeError 错误,否则 __getattr__ 方法不会被调用了。如果在 __getattribute__(self, attr) 方法下存在通过 self.attr 访问属性,会出现无限递归错误 。如下所示, ClassA 中定义了 __getattribute__ 方法,实例 insA 获取属性时,都会调用 __getattribute__ 返回结果,即使是访问 __dict__ 属性。

class ClassA(object):

    def __init__(self, classname):
        self.classname = classname

    def __getattr__(self, attr):
        return('invoke __getattr__', attr)

    def __getattribute__(self, attr):
        return('invoke __getattribute__', attr)


insA = ClassA('ClassA')
print(insA.__dict__)
# ('invoke __getattribute__', '__dict__')

print(insA.classname)
# ('invoke __getattribute__', 'classname')

print(insA.grade)
# ('invoke __getattribute__', 'grade')

object.__setattr__(self, name, value)

会拦截所有属性的的赋值语句。如果定义了这个方法,self.arrt = value 就会变成self.__setattr__("attr", value).这个需要注意。当在__setattr__方法内对属性进行赋值时,不可使用self.attr = value,因为他会再次调用self.__setattr__("attr", value),则会形成无穷递归循环,最后导致堆栈溢出异常 。应该通过对属性字典做索引运算来赋值任何实例属性,也就是使用self.__dict__['name'] = value.

如果类自定义了 __setattr__ 方法,当通过实例获取属性尝试赋值时,就会调用 __setattr__ 。常规的对实例属性赋值,被赋值的属性和值会存入实例属性字典 __dict__ 中。

class ClassA(object):

    def __init__(self, classname):
        self.classname = classname

insA = ClassA('ClassA')

print(insA.__dict__)
# {'classname': 'ClassA'}

insA.tag = 'insA'    

print(insA.__dict__)
# {'tag': 'insA', 'classname': 'ClassA'}

如果类自定义了 __setattr__ ,对实例属性的赋值就会调用它。类定义中的 self.attr 也同样,所以在 __setattr__ 下还有 self.attr 的赋值操作就会出现无线递归的调用 __setattr__ 的情况。自己实现 __setattr__ 有很大风险,一般情况都还是继承 object 类的 __setattr__ 方法。

class ClassA(object):
    def __init__(self, classname):
        self.classname = classname

    def __setattr__(self, name, value):
        # self.name = value  # 如果还这样调用会出现无限递归的情况
        print('invoke __setattr__')

insA = ClassA('ClassA') # __init__中的self.classname调用__setattr__。
# invoke __setattr__

print(insA.__dict__)
# {}

insA.tag = 'insA'    
# invoke __setattr__

print(insA.__dict__)
# {}

object.__delattr__(self, name)

Like __setattr__() but for attribute deletion instead of assignment. This should only be implemented if del obj.name is meaningful for the object.

object.__dir__(self)

dir()作用在一个实例对象上时, __dir__ 会被调用。 返回值必须是序列 。dir()将返回的序列转换成列表并排序。

object.__call__(self[, args...])

Called when the instance is “called” as a function; if this method is defined, x(arg1, arg2, ...) is a shorthand for x.__call__(arg1, arg2, ...).

Python中有一个有趣的语法,只要定义类型的时候,实现 __call__ 函数,这个类型就成为可调用的。换句话说,我们可以把这个类的对象当作函数来使用,相当于重载了括号运算符。

class Student(object):
    def __init__(self, name):
        self.name = name
    def __call__(self):
        print('My name is %s.' % self.name)
        
s = Student('Michael')
s()
# My name is Michael.

通过使用 __setattr____getattr____delattr__ 可以重写dict,使之通过“.”调用键值。

class Dict(dict):
    '''
    通过使用__setattr__,__getattr__,__delattr__
    可以重写dict,使之通过“.”调用
    '''
    def __setattr__(self, key, value):
        print("In '__setattr__")
        self[key] = value
        
    def __getattr__(self, key):
        try:
            print("In '__getattr__")
            return self[key]
        except KeyError as k:
            return None
            
    def __delattr__(self, key):
        try:
            del self[key]
        except KeyError as k:
            return None
            
    # __call__方法用于实例自身的调用,达到()调用的效果
    def __call__(self, key):    # 带参数key的__call__方法
        try:
            print("In '__call__'")
            return self[key]
        except KeyError as k:
            return "In '__call__' error"
            
s = Dict()
print(s.__dict__)
# {}

s.name = "hello"    # 调用__setattr__
# In '__setattr__

print(s.__dict__) # 由于调用的'__setattr__', name属性没有加入实例属性字典中。
# {}

print(s("name"))    # 调用__call__
# In '__call__'
# hello

print(s["name"])    # dict默认行为
# hello

# print(s)
print(s.name)       # 调用__getattr__
# In '__getattr__
# hello

del s.name          # 调用__delattr__
print(s("name"))    # 调用__call__
# None

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Algorithms + Data Structures = Programs

Algorithms + Data Structures = Programs

Niklaus Wirth / Prentice Hall / 1975-11-11 / GBP 84.95

It might seem completely dated with all its examples written in the now outmoded Pascal programming language (well, unless you are one of those Delphi zealot trying to resist to the Java/.NET dominanc......一起来看看 《Algorithms + Data Structures = Programs》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具