魔法方法
- 魔法方法总是被双下划线包围,例如__init__。
- 魔法方法是面向对象的 Python 的一切,如果你不知道魔法方法,说明你还没能意识到面向对象的 Python 的强大。
- 魔法方法的“魔力”体现在它们总能够在适当的时候被自动调用。
- 魔法方法的第一个参数应为cls(类方法) 或者self(实例方法)。
cls:代表一个类的名称
self:代表一个实例对象的名称
基本的魔法方法
- init(self[, …]) 构造器,当一个实例被创建的时候调用的初始化方法
class Re:
def __init__(self,x,y):
self.x=x
self.y=y
def c(self):
return (self.x+self.y)*2
def s(self):
return self.x*self.y
r1=Re(3,4)
print(r1.c())#14
print(r1.s())#12
- new(cls[, …]) 在一个对象实例化的时候所调用的第一个方法,在调用__init__初始化前,先调用__new__。
1.new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由 Python 解释器自动提供,后面的参数直接传递给__init。
2.new__对当前类进行了实例化,并将实例返回,传给__init__的self。但是,执行了__new,并不一定会进入__init__,只有__new__返回了,当前类cls的实例,当前类的__init__才会进入。
class A(object):
def __init__(self, value):
print("into A __init__")
print(self.value)
self.value = value
def __new__(cls, *args, **kwargs):
print("into A __new__")
print(cls)
return object.__new__(cls)
class B(A):
def __init__(self, value):
print("into B __init__")
self.value = value
def __new__(cls, *args, **kwargs):
print("into B __new__")
print(cls)
return super().__new__(cls, *args, **kwargs)
b = B(13)
#into B __new__
<class '__main__.B'>
into A __new__
<class '__main__.B'>
into B __init__
class A(object):
def __init__(self, value):
print("into A __init__")
self.value = value
def __new__(cls, *args, **kwargs):
print("into A __new__")
print(cls)
return object.__new__(cls)
class B(A):
def __init__(self, value):
print("into B __init__")
self.value = value
def __new__(cls, *args, **kwargs):
print("into B __new__")
print(cls)
return super().__new__(A, *args, **kwargs) # 改动了cls变为A
b = B(10)
# into B __new__
# <class '__main__.B'>
# into A __new__
# <class '__main__.A'>
-若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行,将没有__init__被调用。
例:(利用__new__实现单例模式。)
class A:
pass
x=A()
y=A()
print(id(x),id(y))#1825303356272 1825303764752
class A:
__temp=None
def __new__(cls):
if cls.__temp is None:
cls.__temp=object.__new__(cls)
return cls.__temp
else:
return cls.__temp
x=A()
y=A()
print(id(x),id(y))#1825303764032 1825303764032
- __new__方法主要是当你继承一些不可变的 class 时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。
class Exchange(str):
def __new__(cls,string):
string=string.lower()
return str.__new__(cls,string)
x=Exchange("I LOVE PYTHON")
print(x)
#i love python
-str(self):
1.当你打印一个对象的时候,触发__str__
2.当你使用%s格式化的时候,触发__str__
3.str强转数据类型的时候,触发__str__
- repr(self):
1.repr是str的备胎
2.有__str__的时候执行__str__,没有实现__str__的时候,执行__repr__
3.repr(obj)内置函数对应的结果是__repr__的返回值
4.当你使用%r格式化的时候 触发__repr__
class Dog:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return "name is {0},age is {1}.".format(self.name,self.age)
def __repr__(self):
return "dog:{0},age:{1}".format(self.name,self.age)
def eat(self):
print("{0} is eating...".format(self.name))
def drink(self):
print("{0} is drinking...".format(self.name))
keke=Dog("Keke",4)
print(keke)
print(str(keke))
print(repr(keke))
keke.eat()
#name is Keke,age is 4.
#name is Keke,age is 4.
#dog:Keke,age:4
#Keke is eating...
<注>
str(self) 的返回结果可读性强。也就是说,str 的意义是得到便于人们阅读的信息,就像下面的 ‘2019-10-11’ 一样。
repr(self) 的返回结果应更准确。怎么说,repr 存在的目的在于调试,便于开发者使用。
import datetime
today = datetime.date.today()
print(str(today))
print(repr(today))
print('%s' %today)
print('%r' %today)
#2020-08-05
#datetime.date(2020, 8, 5)
#2020-08-05
#datetime.date(2020, 8, 5)
算术运算符
- add(self, other)定义加法的行为:+
- sub(self, other)定义减法的行为:-
class Locat:
def __init__(self,x,y):
self.x=x
self.y=y
def __add__(self,others):
return Locat(self.x+others.x,self.y+others.y)
def __sub__(self,others):
return Locat(self.x-others.x,self.y-others.y)
def prt(self):
print("location:x={0},y={1}".format(self.x,self.y))
def myfunction():
a=Locat(x=1,y=2)
a.prt()
b=Locat(x=3,y=4)
b.prt()
c=a-b
c.prt()
if __name__=='__main__':
myfunction()
#location:x=1,y=2
#location:x=3,y=4
#location:x=-2,y=-2
类似的:
mul(self, other)定义乘法的行为:*
truediv(self, other)定义真除法的行为:/
floordiv(self, other)定义整数除法的行为://
mod(self, other) 定义取模算法的行为:%
divmod(self, other)定义当被 divmod() 调用时的行为
divmod(a, b)把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)。
print(divmod(9,4))
#(2, 1)
反算术运算符
反运算魔方方法,与算术运算符保持一一对应,不同之处就是反运算的魔法方法多了一个“r”。当文件左操作不支持相应的操作时被调用。
增量赋值运算符
- iadd(self, other)定义赋值加法的行为:+=
- isub(self, other)定义赋值减法的行为:-=
- imul(self, other)定义赋值乘法的行为:*=
- itruediv(self, other)定义赋值真除法的行为:/=
- ifloordiv(self, other)定义赋值整数除法的行为://=
- imod(self, other)定义赋值取模算法的行为:%=
- ipow(self, other[, modulo])定义赋值幂运算的行为:**=
- ilshift(self, other)定义赋值按位左移位的行为:<<=
- irshift(self, other)定义赋值按位右移位的行为:>>=
- iand(self, other)定义赋值按位与操作的行为:&=
- ixor(self, other)定义赋值按位异或操作的行为:^=
- ior(self, other)定义赋值按位或操作的行为:|=
一元运算符
- neg(self)定义正号的行为:+x
- pos(self)定义负号的行为:-x
- abs(self)定义当被abs()调用时的行为
- invert(self)定义按位求反的行为:~x
属性访问
- getattr(self, name): 定义当用户试图获取一个不存在的属性时的行为。
- getattribute(self, name):定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用__getattr__)。
- setattr(self, name, value):定义当一个属性被设置时的行为。
- delattr(self, name):定义当一个属性被删除时的行为。
class A:
def __gettattribute__(self,item):
print("__gettattribute__")
return super().__getattribute__(item)
def __getattr__(self,item):
print("__getattr__")
def __setattr__(self,key,value):
print("__setattr__")
super().__setattr__(key,value)
def __delattr__(self, item):
print('__delattr__')
super().__delattr__(item)
a=A()
a.x
#__getattr__
a.x=1
#__setattr__
del a.x
#__delattr__
描述符
描述符就是将某种特殊类型的类的实例指派给另一个类的属性。
- get(self, instance, owner)用于访问属性,它返回属性的值。
- set(self, instance, value)将在属性分配操作中调用,不返回任何内容。
- del(self, instance)控制删除操作,不返回任何内容。
class MyDecriptor:
def __get__(self, instance, owner):
print('__get__', self, instance, owner)
def __set__(self, instance, value):
print('__set__', self, instance, value)
def __delete__(self, instance):
print('__delete__', self, instance)
class Test:
x = MyDecriptor()
t = Test()
t.x #__get__ <__main__.MyDecriptor object at 0x000002196985E370> <__main__.Test object at 0x00000219698C1F10> <class '__main__.Test'>
t.x = 'x-man' #__set__ <__main__.MyDecriptor object at 0x000002196985E370> <__main__.Test object at 0x00000219698C1F10> x-man
del t.x #__delete__ <__main__.MyDecriptor object at 0x000002196985E370> <__main__.Test object at 0x00000219698C1F10>
迭代器
- 是访问集合元素的一种方式
- 迭代器是一个可以记住遍历的位置的对象。
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
- 迭代器只能往前不会后退。
- 字符串,列表或元组对象都可用于创建迭代器:
d={1:"a",2:"b",3:"c"}
for each in d:
print("{0}->{1}".format(each,d[each]))
#1->a
#2->b
#3->c
1.迭代器有两个基本的方法:iter() 和 next()。
2.iter(object) 函数用来生成迭代器。
3.next(iterator[, default]) 返回迭代器的下一个项目。
4.iterator – 可迭代对象
5.default – 可选,用于设置在没有下一个元素时返回该默认值,如果不6.设置,又没有下一个元素则会触发 StopIteration 异常。
links = {1: 'a', 2: 'b', 3: 'c'}
it = iter(links)
print(next(it)) #1
print(next(it)) #2
print(next(it)) #3
print(next(it)) #StopIteration
把一个类作为一个迭代器使用需要在类中实现两个魔法方法 iter() 与 next() 。
iter(self)定义当迭代容器中的元素的行为,返回一个特殊的迭代器对象, 这个迭代器对象实现了 next() 方法并通过 StopIteration 异常标识迭代的完成。
next() 返回下一个迭代器对象。
StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 next() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。
生成器
1.在 Python 中,使用了 yield 的函数被称为生成器(generator)。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
2.在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
3.调用一个生成器函数,返回的是一个迭代器对象。
def myGen():
print('生成器执行!')
yield 1
yield 2
myG = myGen()
print(next(myG))
# 生成器执行!
# 1
print(next(myG)) # 2
print(next(myG)) # StopIteration