【python】魔术方法1

举报
子都爱学习 发表于 2021/12/17 22:12:21 2021/12/17
【摘要】 简介魔法方法就是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而这一切都是自动发生的。它们经常是两个下划线包围来命名的(比如 __init__,__lt__),Python的魔法方法是非常强大的,所以了解其使用方法也变得尤为重要!__dir____dir__ 返回类或者对象的所有...

简介

魔法方法就是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而这一切都是自动发生的。它们经常是两个下划线包围来命名的(比如 __init__,__lt__),Python的魔法方法是非常强大的,所以了解其使用方法也变得尤为重要!

5db64101d5d4a715.jpg

__dir__

__dir__ 返回类或者对象的所有成员名称列表 
dir()操作的实例就是调用__dir__()
类中没有实现__dir__(),该方法将最大程度收集属性信息

# animal.py
class Animal:
    x=123
    def __init__(self, name):
        self.name=name
        self.age = 10
        self.weight = 20

# dir()作用是模块对象时,返回模块的属性名和变量名
print('animal Module :{}'.format(dir()))     # 当模块被导入时执行
# animal Module :['Animal', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
# cat.py
import animal
from animal import Animal

class Cat(Animal):
    x = "cat"
    y = 'abcd'

class Dog(Animal):
    def __dir__(self):
        return ['dog']   # 必须返回可迭代对象
cat = Cat('tom')
dog = Dog('wangwang')
print(cat.__dir__())
# ['name', 'age', 'weight', '__module__', 'x', 'y', '__doc__', '__init__', '__dict__', '__weakref__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']

print(dog.__dir__())
# ['dog']


print(globals())
print(locals())
print(Cat.__dict__)
#'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10135cca0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/Users/chengzhilin/Desktop/workspace/魔术方法之反射.py', '__cached__': None, 'animal': <module 'animal' from '/Users/chengzhilin/Desktop/workspace/animal.py'>, 'Animal': <class 'animal.Animal'>, 'Cat': <class '__main__.Cat'>, 'Dog': <class '__main__.Dog'>, 'cat': <__main__.Cat object at 0x10144ad90>, 'dog': <__main__.Dog object at 0x10144ad30>}
# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10135cca0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/Users/chengzhilin/Desktop/workspace/魔术方法之反射.py', '__cached__': None, 'animal': <module 'animal' from '/Users/chengzhilin/Desktop/workspace/animal.py'>, 'Animal': <class 'animal.Animal'>, 'Cat': <class '__main__.Cat'>, 'Dog': <class '__main__.Dog'>, 'cat': <__main__.Cat object at 0x10144ad90>, 'dog': <__main__.Dog object at 0x10144ad30>}
# {'__module__': '__main__', 'x': 'cat', 'y': 'abcd', '__doc__': None}

拓展:
globals():获取当前模块全局变量的字典
locals():返回当前作用域的变量字典
dir() :返回属性名和变量名的列表
__dict__:返回属性名和变量名的字典,类似于dir()


实例化:__new__

实例化一个对象
该方法需要返回一个值,如果该值不是cls的实例,则不会调用 __init__
该方法永远都是静态方法
class A:
    def __new__(cls, *args, **kwargs):
        print(cls)
        print(args)
        print(kwargs)
        # class '__main__.A'>
        # ()
        # {}
        
        #return super().__new__(cls)
        #return 1
        return None

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


a = A()
print(a)
# None
__new__ 方法很少使用,即使创建了该方法,也会使用 return super().__new__(cls) 基类object
__new__ 方法来创建实例并返回。

__init__(self[,...])

构造器,当一个实例被创建的时候调用的初始化方法(实例方法)

__del__方法

销毁魔术方法
触发时机:当一个对象在内存中被销毁的时候自动执行
参数:至少有一个self,接收对象
返回值:无
作用:在对象销毁的时候做一些操作
注意:程序自动调用此方法,不需要我们手动调用。

每个Pythoner都知道一个最基本的魔术方法, __init__ 。通过此方法我们可以定义一个对象的初始操作。然而,当调用 x = SomeClass() 的时候, __init__ 并不是第一个被调用的方法。实际上,还有一个叫做__new__ 的方法,两个共同构成了“构造函数”。__new__是用来创建类并返回这个类的实例, 而__init__只是将传入的参数来初始化该实例。在对象生命周期调用结束时,__del__ 方法会被调用,可以将__del__理解为“构析函数”。



可视化

 __str__

str()函数、  format()函数、  print()函数调用,需要返回对象的字符串表达。如果没 有定义,就去调用 __repr__ 方法返回字符串表达,如果 __repr__ 没有定义,就 直接返回对象的内存地址信

 __repr__

内建函数repr()对一个对象获取字符串表达

调用 __repr__ 方法返回字符串表达,如果 __repr__ 也没有定义,就直接返回 object的定义就是显示内存地址信息

__bytes__

bytes()函数调用,返回一个对象的bytes表达即返回bytes对象


class A:
    def __init__(self, name, age=18):
        self.name = name
        self.age = age

    def __repr__(self):
        return 'repr: {},{}' .format(self.name, self.age)

    def __str__(self):
        return 'str:  {},{}' .format(self.name, self.age)

    def __bytes__(self):
        #return "{} is {}".format(self.name, self.age).encode()

        import json
        return json.dumps(self.__dict__).encode()

# print函数使用__str__
print(A('tom'))
print('{}'.format(A('tom')))
print([A('tom')]) # []使用__str__,但其内部使用__repr__
print([str(A('tom'))]) # []使用__str__,其中的元素使用str()函数也调用__str__
print(bytes(A('tom')))

# str:  tom,18
# str:  tom,18
# [repr: tom,18]
# ['str:  tom,18']
# b'{"name": "tom", "age": 18}'


bool

 

__bool__

内建函数bool(),或者对象放在逻辑表达式的位置调用这个函数返回布尔值 没有定义 __bool__ ()就找__len__ ()返回长度,非0为真。

如果 __len__ ()也没有定义那么所有实例都返回真

class A: pass
print(bool(A))     
print(bool(A()))   # A的定义 __bool__,__len__都未定义,全部返回真
# True
# True

class B:
    def __bool__(self):
        return False
print(bool(B))
print(bool(B()))   # bool()调用方法__bool__,而__bool__返回Fasle
# True
# False
if B():
    print('Real B instance')

class C:
    def __len__(self):
        return 0

print(bool(C))
print(bool(C()))    # bool()调用方法__bool__,没有定义,继续调用__len__,而__len__返回长度0
# True
# False
if C():
    print('Real C instance')


运算符重

运算符

殊方法

<, <=, ==, >, >=, !=

__lt__ ,  __le__ ,  __eq__ ,  __gt__ ,  __ge__ ,

__ne__

比较运算

+, -, *, /, %,

//, **,

divmod

__sub__ ,  __mul__ ,  __truediv__ ,       __floordiv__ ,  __pow__ ,  __divmod__

算数运算符移位、 位运算也有对应的方 

+=, -=, *=,

/=, %=, //=,

**=

__isub__ ,  __imul__ ,  __itruediv__ ,

__ifloordiv__ ,  __ipow__

 

 

class A:pass

print(A() == A())    #比较内存地址
# False
print(A() > A())    # A没有定义 >
# TypeError: '>' not supported between instances of 'A' and 'A'
class A:
    def __init__(self, name, age=18):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return self.name == other.name and self.age == other.age

    def __gt__(self, other):
        return self.age > other.age

    def __ge__(self, other):
        return self.age >= other.age

tom = A('tom')
jerry = A('jerry', 16)
print(tom == jerry, tom != jerry)   # __eq__实现
print(tom > jerry, tom < jerry)      # __gt__实现
print(tom >= jerry, tom <= jerry)  # __ge__实现

# False True
# True False
# True False

__eq__ 于可以推断不等于
__gt__ 大于可以推断小于
__ge__ 大于等于可以推断小于等于

容器相关方法

方法

意义

 

 

     len__

内建函数len(),返回对象的长度(>=0的整数),如果把对象当做容器类型 看,就如同list或者dict

bool()函数调用的时候,如果没有 bool () 方法,则会看 len () 方法

是否存在,存在返回非0为真

 

     iter__

迭代容器时,调用,返回一个新的迭代器对象

 

     contains__

in 成员运算符,没有实现,就调用   iter  方法遍历

 

     getitem__

实现self[key]访问。序列对象,key接受整数为索引,或者切片。对于setdictkeyhashablekey不存在引发KeyError异常

 

     setitem__

    getitem  的访问类似,是设置值的方法

 

     missing__

字典或其子类使用 getitem () 调用时,key不存在执行该方法

 

class A(dict):
    def __missing__ (self, key):
        print('Missing key : ', key)
        return 0

a = A()
print(a['k'])   # a['k']不存在调用 __missing__,函数返回0,所以print打印0
# Missing key :  k
# 0
class Cart:
    def __init__(self):
        self.items = []

    def __len__(self):
        return len(self.items)

    def additem(self, item):
        self.items.append(item)

    def __iter__(self):
        # yield from self.items
        return iter(self.items)

    def __getitem__(self, index): # 索 引 访 问
        return self.items[index]

    def __setitem__(self, key, value):  # 索引赋值
        self.items[key] = value

    def __str__(self):
        return str(self.items)

    def __add__(self, other): # +
        self.items.append(other)
        return self

cart = Cart() # 长度、bool
print(cart, bool(cart), len(cart))
# [] False 0

cart.additem(1)
cart.additem('abc')
cart.additem(3)

# 长度、bool
print(cart, bool(cart), len(cart))
# [1, 'abc', 3] True 3

# 迭代
for x in cart:
    print(x)

# in
print(3 in cart)
print(2 in cart)
# True
# False

# 索引操作
print(cart[1])
cart[1] = 'xyz'
print(cart)
# abc
# [1, 'xyz', 3]

# 链式编程实现加法
print(cart + 4 + 5 + 6)
print(cart.__add__(17).__add__(18))
# [1, 'xyz', 3, 4, 5, 6]
# [1, 'xyz', 3, 4, 5, 6, 17, 18]


可调用对象

__call__

类中定义一个该方法  实例就可以像函数一样调用


Python中一切皆对象,函数也不例外。
def foo():
    print(foo.__module__, foo.__name__)

foo()
# __main__ foo

# 等价于
foo.__call__()
# __main__ foo
函数即对象,对象foo加上(),就是调用此函数对象的 __call__() 方法

可调用对象:定义一个类,并实例化得到其实例,将实例像函数一样调用

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __call__(self, *args, **kwargs):
        return "<Point {}:{}>" .format(self.x, self.y)

p = Point(4, 5)
print(p)
# <__main__.Point object at 0x0000021197B17FD0>
print(p())  #调用__call__
# <Point 4:5>

# 累加
class Adder:
    def __call__(self, *args):
        self.result = sum(args)
        return self.result

adder = Adder()
print(adder(*range(4, 7)))
print(adder.result)
# 15
# 15


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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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