Python--魔法方法(部分)

1、__call__

如果在类中实现了 __call__ 方法,那么实例对象也将成为一个可调用对象

什么是可调用对象?

可调用对象:但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable

这个魔法方法可以让类的实例行为表现的像函数一样

示例:
 

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

    def __call__(self):
        self.x, self.y = self.y, self.x
        return self.x, self.y
demo = Demo(1, 2)  # 创建实例
res = demo()  # 实例可以象函数那样执行,并传入x y值,修改对象的x y
print(res)  # (2, 1)

 

2、__getattr__

动态返回一个属性,当调用不存在的属性时,Python会试图调用__getattr__(self,'key')来获取属性,并且返回key。

class Student(object):
    def __getattr__(self, item):
        return item


x = Student()
print(x.age)  # age
print(x.name)  # name

 

3、__getattribute__

当每次调用属性时,python会无条件进入__getattribute__中,不论属性存在与否,这就是与__getattr__的区别

必须特别小心 __getattribute__ 方法,因为 Python 在查找类的方法名称时也将对其进行调用

class Student(object):
    def __getattr__(self, item):
        return "__getattr__ run...", item
    def __getattribute__(self, item):
        return "__getattribute__ run...", item

x = Student()
print(x.age)  # ('__getattribute__ run...', 'age')
print(x.name)  # ('__getattribute__ run...', 'name')

__getattribute__与__getattr__区别:

每次实例访问属性,都会经过__getattribute__函数。而当属性不存在时,仍然需要访问__getattribute__,不过接着要访问__getattr__。这就好像是一个异常处理函数。

示例:
 

class Student(object):
    age = 18

    def __getattr__(self, item):
        print("not exist", item)
        return "__getattr__ run...", item
    def __getattribute__(self, item):
        # 此处为了让其找到属性后调用object的默认__getattribute__进行返回
        # 否则会引发超过最大递归次数的异常
        print("__getattribute__ run...")
        return object.__getattribute__(self, item)

x = Student()
print(x.age)
print("-" * 40)
print(x.name)

结果如下:

__getattribute__ run...
18
----------------------------------------
__getattribute__ run...
not exist name
('__getattr__ run...', 'name')

 

4、__setattr__

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

class Demo(dict):

    def __getattr__(self, key):
        # 继承dict类
        return self[key]

    def __setattr__(self, key, value):
        # 改变赋值行为
        self[key] = value

x = Demo()
x.age = 100
print(x.age)

 

5、__dict__

返回对象具有的属性与方法。对于类,是返回其全部属性与方法,对于类实例,只返回定义好的属性

ps:__dict__是dir()函数的子集,dir函数会自动寻找该对象的属性与方法(包括从父类中继承的属性)

示例

class Demo():
    a = 1
    b = 2
    def __init__(self):
        self.name = 'cc'
        self.__dict__['age'] = 18
    def demo(self):
        pass
    
print(Demo.__dict__)  # 可以打印出全部属性与方法地址
d = Demo()
print(d.__dict__)  # 只能打印self的属性
print(dir(d))

{'__module__': '__main__', 'a': 1, 'b': 2, '__init__': <function Demo.__init__ at 0x1038a1700>, 'demo': <function Demo.demo at 0x1038a18b0>, '__dict__': <attribute '__dict__' of 'Demo' objects>, '__weakref__': <attribute '__weakref__' of 'Demo' objects>, '__doc__': None}


{'name': 'cc', 'age': 18}


['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'age', 'b', 'demo', 'name']
 

 

6、__SLOTS__

允许类可以获得的属性,不能动态的添加其他的属性

示例

class Demo():
    __slots__ = ('age', 'name')


d = Demo()
d.age = 18
print(d.age)
d.name = "xx"
print(d.name)
d.id=1
print(d.id) # 异常

 

 

7、__setitem__

拦截所有字典类型的赋值,需要init方法配合使用,避免出现超出最大递归深度

class Demo():
    def __init__(self):
        self.dict = dict()

    def __setitem__(self, key, value):
        print(key+"...")
        self.dict[key] = value

    def __getitem__(self, key):
        print('调用getitem')
        return self.dict[key]

d = Demo()
d["name"] = "xx"

 

8、__contains__

判断操作的时候会自动调用这个函数。

class Demo():
    def __init__(self, list):
        self.list = list

    def __contains__(self, item):
        print("contains run...")
        return item in self.list

d = Demo([1,2,3])
res = d.__contains__(1)
print(res) # 因为__contains__定义返回的是一个表达式,所以此处返回ture

if 2 in d:
    pass

结果

contains run...
True
contains run...

 

9、__iter__和__next__

一个类,实现了__iter__,那么就认为它有迭代能力,通常此函数必须返回一个实现了__next__的对象,如果自己实现了,你可以返回self,这个返回值不是必须的;

注意,如果只实现了__iter__,那么它是迭代对象,只有同时实现了__iter____next__才是迭代器。

自定义可迭代对象示例

class Myiterator(object):
    def __init__(self, mylist):
        self.my_list = mylist
        self.current_index = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.current_index < len(self.my_list):
            self.current_index += 1
            return self.my_list[self.current_index - 1]
        else:
            raise StopIteration

class MyList(object):
    def __init__(self):
        self.my_list = list()
    def append_item(self, item):
        self.my_list.append(item)
    def __iter__(self):
        my_iterator = Myiterator(self.my_list)
        return my_iterator

m = MyList()
m.append_item(1)
m.append_item(2)

for item in m:
    print(item) 

结果为1,2

 

自定义迭代器示例

class Myiterator(object):
    def __init__(self, mylist):
        self.my_list = mylist
        self.current_index = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.current_index < len(self.my_list):
            self.current_index += 1
            return self.my_list[self.current_index - 1]
        else:
            raise StopIteration


m = Myiterator([1,2,3])
print(next(m))
print(next(m))

结果也为1,2

 

tips:python可以在魔法方法中调用内置方法

举个简单的例子

class Demo(object):
    def __init__(self):
        self.a = [1,2,3]
    def __len__(self):
        return len(self.a)

d = Demo()
print(len(d)) # 3

 

如果对你有帮助,可否在文章右侧点个赞再走呢~~

 

本文为原创,转载请注明出处

 

python 如何避免大量的if else

python complex函数

python避坑篇

python部分高级用法

python开发手册

python内置函数(下)

python内置属性,函数

python异常处理

python lambda函数​​​​​​​

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章