【python】魔术方法1
简介
魔法方法就是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而这一切都是自动发生的。它们经常是两个下划线包围来命名的(比如 __init__,__lt__),Python的魔法方法是非常强大的,所以了解其使用方法也变得尤为重要!
__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__
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
__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接受整数为索引,或者切片。对于set和dict,key为hashable。key不存在引发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__ |
类中定义一个该方法, 实例就可以像函数一样调用 |
def foo():
print(foo.__module__, foo.__name__)
foo()
# __main__ foo
# 等价于
foo.__call__()
# __main__ foo
可调用对象:定义一个类,并实例化得到其实例,将实例像函数一样调用。
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
- 点赞
- 收藏
- 关注作者
评论(0)