python魔法方法
1.基本的魔法方法
(1)__init__方法
用于对实例进行初始化,在实例创建是会自动执行。
class Hello():
def __init__(self):
print("Hello World!")
a = Hello()
#Hello World!
如上,无需调用该方法,在创建实例的时候自动执行了该函数。
(2)__new__方法
该方法是类实例化是第一个调用的方法,__new__
至少要有一个参数cls
,代表要实例化的类,对当前类进行实例化,并返回一个实例给__init__
方法进行初始化。
如下:
class A():
def __init__(self):
print("A")
def __new__(cls, *args, **kwargs):
print("a")
return object.__new__(cls)
a = A()
#a
#A
可以看到__new__
的执行在__init__
前。
如果我们写的类没有写__new__
方法,python会默认执行父类的__new__
方法,父类也没有该方法,那么会一直按此规矩追溯至object
的__new__
方法,因为object
是所有类的父类。所以我们写类并用到该方法时
__new__
方法还可以返回其他类的实例,这样当前类的实例就无法通过当前类的__init__
进行初始化。
因此,执行了__new__
,并不一定会进入__init__
,只有__new__
返回了,当前类cls
的实例,当前类的__init__
才会进入。
如下:
class A():
def __init__(self):
print("A")
def __new__(cls, *args, **kwargs):
print("a")
return object.__new__(cls)
class B():
def __init__(self):
print("B")
def __new__(cls, *args, **kwargs):
print("b")
return object.__new__(A)
b = B()
#b
输出结果只有b
,说明类B中的__init__
方法没有被调用。
实现单例模式
__new__
可以用来实现单例模式,单例模式就是一个类只能有一个实例
这里引用一段代码:
class Earth:
pass
a = Earth()
print(id(a)) # 260728291456
b = Earth()
print(id(b)) # 260728291624
class Earth:
__instance = None # 定义一个类属性做判断
def __new__(cls):
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance
else:
return cls.__instance
a = Earth()
print(id(a)) # 512320401648
b = Earth()
print(id(b)) # 512320401648
这里可以看到,第一次实例化a
,b
他们的地址不一样,说明是两个实例,而重构Earth
类后,再次实例化地址相同。
自定义类的实例化
__new__
方法主要是当我们继承一些不可变的 class 时(比如int, str, tuple
), 提供一个自定义这些类的实例化过程的途径。
class add(int):
def __new__(cls, integer):
integer += 1
return int.__new__(cls, integer)
a = add(1)
print(a)
#2
而如果没有该方法,应该输出的是1,而不是2。
(3)__del__方法
当需要删除对象来释放类所占用的资源的时候,就需要调用析构方法__del__()。我们可以手动销毁释放内存,或由python自动帮我们销毁。
class CLanguage:
def __init__(self):
print("调用 __init__() 方法构造对象")
def __del__(self):
print("调用__del__() 销毁对象,释放其空间")
clangs = CLanguage()
#调用 __init__() 方法构造对象
#调用__del__() 销毁对象,释放其空间
如果加上:
del clangs
结果与上述相同。
但有时即使我们手动销毁也不会立即释放该实例的内存。
这里引用一段代码:
class CLanguage:
def __init__(self):
print("调用 __init__() 方法构造对象")
def __del__(self):
print("调用__del__() 销毁对象,释放其空间")
clangs = CLanguage()
#添加一个引用clangs对象的实例对象
cl = clangs
del clangs
print("***********")
#调用 __init__() 方法构造对象
#***********
#调用__del__() 销毁对象,释放其空间
可以看到,我们使用了del但却是再最后输出,没有立即释放内存,这与python的垃圾回收机制有关。
(4)__str__方法和__repr__方法
__str__方法:
当你打印一个对象的时候,触发__str__
当你使用%s
格式化的时候,触发__str__
str
强转数据类型的时候,触发__str__
__repr__方法:
repr
是str
的备胎
有__str__
的时候执行__str__
,没有实现__str__
的时候,执行__repr__
repr(obj)
内置函数对应的结果是__repr__
的返回值
当你使用%r
格式化的时候 触发__repr__
区别str更加易读,repr更加准确适合调试。
算术运算符
类型工厂函数
指的是“不通过类而是通过函数来创建对象”。在python2.2之前类与类型分开,类是封装起来的属性与方法,类型是如整型、浮点型、字符型。但之后两者统一了int()
、str()
、list()
就成了类型工厂函数。如下面的例子:
class C:
pass
print(type(len)) # <class 'builtin_function_or_method'>
print(type(dir)) # <class 'builtin_function_or_method'>
print(type(int)) # <class 'type'>
print(type(list)) # <class 'type'>
print(type(tuple)) # <class 'type'>
print(type(C)) # <class 'type'>
显示结果都为类。
__add__方法和__sub__方法
分别定义加法和减法,也就是当出现实例间的+
和·-
是,会分别执行这两种魔法方法。
具体用法如下:
class A():
def __init__(self, n):
self.n = int(n)
def __add__(self, other):
return A(self.n + other.n)
def __sub__(self, other):
return A(self.n - other.n)
a = A(1)
b = A(2)
c = a - b
d = a + b
print(c.n, d.n)
#-1 3
这就是给实例的计算提供了方法。
下面有个有趣的例子:
class Int(int):
def __add__(self, other):
return int.__sub__(self, other)
def __sub__(self, other):
return int.__add__(self, other)
a = Int(3)
b = Int(4)
print(a + b, a - b)
#-1 7
这里我们看到加法与减法颠倒了。
除以上两种,还有其他常见的算术运算符如下:
1.__mul__(self, other)
定义乘法的行为:*
2.__truediv__(self, other)
定义真除法的行为:/
3.__floordiv__(self, other)
定义整数除法的行为://
4.__mod__(self, other)
定义取模算法的行为:%
5.__divmod__(self, other)
定义当被 divmod()
调用时的行为,divmod(a, b)
就是把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)
.
6.__pow__(self, other[, module])
定义当被 power()
调用或 **
运算时的行为
7.__lshift__(self, other)
定义按位左移位的行为:<<
8.__rshift__(self, other)
定义按位右移位的行为:>>
9.__and__(self, other)
定义按位与操作的行为:&
10.__xor__(self, other)
定义按位异或操作的行为:^
11.__or__(self, other)
定义按位或操作的行为:|
反算术运算符
与算术运算符一一对应,但是前面多了一个r,当文件左操作不支持相应的操作时被调用。如a+b
时,如果a
对象的__add__()
方法没有实现或者不支持相应的操作,那么 Python 就会调用b
的__radd__()
方法。
1.__radd__(self, other)
定义加法的行为:+
2.__rsub__(self, other)
定义减法的行为:-
3.__rmul__(self, other)
定义乘法的行为:*
4.__rtruediv__(self, other)
定义真除法的行为:/
5.__rfloordiv__(self, other)
定义整数除法的行为://
6.__rmod__(self, other)
定义取模算法的行为:%
7.__rdivmod__(self, other)
定义当被 divmod() 调用时的行为
8.__rpow__(self, other[, module])
定义当被 power() 调用或 **
运算时的行为
9.__rlshift__(self, other)
定义按位左移位的行为:<<
10.__rrshift__(self, other)
定义按位右移位的行为:>>
11.__rand__(self, other)
定义按位与操作的行为:&
12.__rxor__(self, other)
定义按位异或操作的行为:^
13.__ror__(self, other)
定义按位或操作的行为:|
增量赋值运算符
1.__iadd__(self, other)
定义赋值加法的行为:+=
2.__isub__(self, other)
定义赋值减法的行为:-=
3.__imul__(self, other)
定义赋值乘法的行为:*=
4.__itruediv__(self, other)
定义赋值真除法的行为:/=
5.__ifloordiv__(self, other)
定义赋值整数除法的行为://=
6.__imod__(self, other)
定义赋值取模算法的行为:%=
7.__ipow__(self, other[, modulo])
定义赋值幂运算的行为:**=
8.__ilshift__(self, other)
定义赋值按位左移位的行为:<<=
9.__irshift__(self, other)
定义赋值按位右移位的行为:>>=
10.__iand__(self, other)
定义赋值按位与操作的行为:&=
11.__ixor__(self, other)
定义赋值按位异或操作的行为:^=
12.__ior__(self, other)
定义赋值按位或操作的行为:|=
一元运算符
1.__neg__(self)
定义正号的行为:+x
2.__pos__(self)
定义负号的行为:-x
3.__abs__(self)
定义当被abs()
调用时的行为
4.__invert__(self)
定义按位求反的行为:~x
属性访问
1.__getattr__(self, name)
: 定义当用户试图获取一个不存在的属性时的行为。
2.__getattribute__(self, name)
:定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用__getattr__
)。
3.__setattr__(self, name, value)
:定义当一个属性被设置时的行为。
4.__delattr__(self, name)
:定义当一个属性被删除时的行为。
描述符
1.__get__(self, instance, owner)
用于访问属性,它返回属性的值。
2.__set__(self, instance, value)
将在属性分配操作中调用,不返回任何内容。
3.__del__(self, instance)
控制删除操作,不返回任何内容。
定制序列
1,__len__(self)
定义当被len()
调用时的行为(返回容器中元素的个数)。
2.__getitem__(self, key)
定义获取容器中元素的行为,相当于self[key]
。
3.__setitem__(self, key, value)
定义设置容器中指定元素的行为,相当于self[key] = value
。
4.__delitem__(self, key)
定义删除容器中指定元素的行为,相当于del self[key]
。
迭代器
特点
- 迭代是 Python 最强大的功能之一,是访问集合元素的一种方式。
- 迭代器是一个可以记住遍历的位置的对象。
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
- 迭代器只能往前不会后退。
- 字符串,列表或元组对象都可用于创建迭代器:
方法
迭代器有两个方法
iter(object)
函数用来生成迭代器。next(iterator[, default])
返回迭代器的下一个项目。