资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

30面向对象5_运算符重载-容器相关方法-可调用对象-创新互联

目录

创新互联公司主要从事网站制作、成都网站制作、网页设计、企业做网站、公司建网站等业务。立足成都服务管城,十载网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:028-86922220

运算符重载...1

容器相关方法...4

可调用对象...6

运算符重载

可大大提高类的可用性;

锦上添花的东西;

好的类的设计应提供类似的方法;

Operator模块提供以下特殊方法,可将类的实例使用下面的操作符来操作:

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

__lt__,__le__,__eq__,__gt__,__ge__,__ne__

比较运算符,自定义类时用

+,-,*,/,%,//,**,divmod

__add__,__sub__,__mul__,__truediv__,__mod__,__floordiv__,__pow__,__divmod__

算术运算符,移位、位运算符也有对应的方法

+=,-=,*=,/=,%=,//=,**=

__iadd__,__isub__,__imul__,__itruediv__,__imod__,__ifloordiv__,__ipow__


注:

移位、位运算符也有对应的方法,在python中没提升性能,但也没降低性能,其它语言中会大大提升性能;

Int类,几乎实现了所有操作符,可作为参考;

在pycharm中,输入int,ctrl+单击,可查看运算符魔术方法的帮助;

运算符重载应用场景:

往往是用面向对象实现的类,需要做大量的运算;

提供运算符重载(__add__()),比直接提供加法方法(Point类中的add())要更加适合该领域内使用者的习惯,用户在日常用的运算符是在数学上最常见的表达方式,如print(p1 + p2),实现了Point类的二元操作(向量的加法);

例:

class A:

def __init__(self,x):

self.x = x

def __sub__(self, other):

# return self.x - other.x

# return A(self.x - other.x)   #返回一个新对象(new一个新对象)

self.x = self.x - other.x

return self  #就地修改,根据业务场景选择使用

# def __ne__(self, other):

#     return self.x != other.x

def __eq__(self, other):   #判断两对象是否相等用__eq__,一般很少用__ne__

return self.x == other.x

def __repr__(self):

return str(self.x)

__str__ = __repr__   #技巧

def __lt__(self, other):   #也可用__gt__,在测试时缺哪个补哪个;只有实现该方法,才可用sorted()和reversed(),否则报错TypeError: '<' not supported between instances of 'A' and 'A';一般把比较大小的函数写在类内,这样更优雅

return self.x < other.x

def __iadd__(self, other):

# return A(self.x + other.x)

self.x = self.x + other.x

return self  #就地修改

a1 = A(4)

a2 = A(5)

print(a1)

print(a1 - a2)   #等价于print(a1.__sub__(a2))

print(a1)

print(a1.__sub__(a2))

print(a1)

print(a1 == a2)

a3 = A(2)

lst = [a1,a2,a3]

print(lst)

print(sorted(lst))

print(list(reversed(sorted(lst))))

a1 += a2

print(a1)

输出:

4

-1

-1

-6

-6

False

[-6, 5, 2]

[-6, 2, 5]

[5, 2, -6]

-1

习题:

完成Point类设计,实现判断点相等的方法,并完成向量的加法;

class Point:

def __init__(self,x,y):

self.x = x

self.y = y

def __eq__(self, other):

return self.x == other.x and self.y == other.y

def __add__(self, other):

return Point(self.x + other.x,self.y + other.y)   #根据使用者习惯设计

# def __add__(self, other):

#     return (self.x + other.x,self.y + other.y)

def __str__(self):

return 'Point:{},{}'.format(self.x,self.y)

__repr__ = __str__

def add(self,other):

return (self.x + other.x,self.y + other.y)

p1 = Point(1,1)

p2 = Point(1,1)

print(p1,p2)

points = (p1,p2)

print(points[0].add(points[1]))

print(points[0] + points[1])   #类似pathlib.Path中的/

print(Point(*(points[0].add(points[1]))))

# print(Point(*(points[0] + points[1])))

print(p1 == p2)

print(p1 is p2)

输出:

Point:1,1 Point:1,1

(2, 2)

Point:2,2

Point:2,2

True

False

容器相关方法

__len__,内建函数len(),返回对象的长度,>=0的整数,即使把对象当作容器类型看,如list、dict,bool()函数调用的时候,如果没有__bool__()方法,则会看__len__()方法是否存在,存在返回,非0为真;

__iter__,迭代容器时调用,要求返回一个新的迭代器对象iterator;

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

__getitem__,实现self[key]访问,序列对象,key接受整数为索引,或切片,对于set、dict,key为可hashable,key不存在引发KeyError异常;

__setitem__,类似__getitem__,是设置值的方法;

__missing__,字典使用__getitem__()调用时,key不存在执行该方法,如class MyDict(dict): pass;

__len__和__size__并不对等:

__len__,容器中元素的个数;

__size__,容器的大小,第三方库中,当容量快满时,会把size扩展;

__len__和__iter__:

有时并不关心元素有多少个,直接取元素,__iter__用的多些;

注:

single linkedlist中的__getitem__,仅用于容器,提供一种方便的接口,如索引或其它方式来用;

函数中的属性,foo.__defaults__,用元组保存位置参数默认值;

函数中的属性,foo.__kwdefaults__,用元组保存关键字参数默认值;

习题:

将购物车类,改造成方便操作的容器类;

class Color:

RED = 0

GREEN = 1

BLUE = 2

GOLDEN = 3

BLACK = 4

OTHER = 1000

class Item:

def __init__(self,**kwargs):

self.__spec = kwargs

def __repr__(self):

# return str(sorted(self.__spec.items()))

return str(self.__spec)

__str__ = __repr__

class Cart:

def __init__(self):

self.items = []

def additem(self,item:Item):   #兼容__add__,看用户使用要求自定义,要不要return,一般用__add__

self.items.append(item)

def getall(self):

return self.items

def __len__(self):

return len(self.items)

def __add__(self, other):

self.items.append(other)

return self

def __iter__(self):   #要求必须返回迭代器iterator,简化,让使用者觉得实例就是可迭代对象

return iter(self.items)

def __getitem__(self, item):   #该例容器为列表,此处item为索引

return self.items[item]

def __setitem__(self, key, value):   #key为index,value为字典

self.items[key] = value

# self[key] = value

def __repr__(self):

return str(self.items)

__str__ = __repr__

mycart = Cart()

myphone = Item(mark = 'sony',color = Color.BLACK,price=2250)

mybicycle = Item(mark='decathlan',color=Color.BLACK,price=1599)

mykindle = Item(mark='amazon',color=Color.OTHER,price=498)

mycart.additem(myphone)

print(mycart.getall())

print(len(mycart))

print(mycart + mybicycle + mykindle)   #链式编程实现加法,等价于mycart.__add__(mybicycle).__add__(mykindle)

# print(mycart.__add__(mybicycle).__add__(mykindle))

print(len(mycart))

# for x in mycart.items:    #类中没有__iter__方法时使用此种方式迭代实例中的容器

#     print(x)

for x in mycart:   #类中有__iter__方法后,实例就成了可迭代对象,简化,让用户觉得实例就是可迭代对象

print(x)

print(mycart[1])

mycart[1] = {'mark': 'giant', 'color': 4, 'price': 1599}   #此处的value为字典

print(mycart[1])

输出:

[{'mark': 'sony', 'color': 4, 'price': 2250}]

1

[{'mark': 'sony', 'color': 4, 'price': 2250}, {'mark': 'decathlan', 'color': 4, 'price': 1599}, {'mark': 'amazon', 'color': 1000, 'price': 498}]

3

{'mark': 'sony', 'color': 4, 'price': 2250}

{'mark': 'decathlan', 'color': 4, 'price': 1599}

{'mark': 'amazon', 'color': 1000, 'price': 498}

{'mark': 'decathlan', 'color': 4, 'price': 1599}

{'mark': 'giant', 'color': 4, 'price': 1599}

可调用对象

python中一切皆对象,函数也不例外;

__call__,类中实现,实例就可像函数一样调用;

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

一个实例可将其当作函数,进而可当装饰器来用;

例:

def foo(x):   #函数即对象,对象foo加上(),就是调用对象的__call__()方法

 print(x)

print(callable(foo))

foo(4)   #等价于foo.__call__(4)

foo.__call__(4)

print(foo.__name__)

print(foo.__doc__)

print(foo.__dict__)

print(foo.__call__)

print(dir(foo))

输出:

True

4

4

foo

None

{}

['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

例:

class A:

def __call__(self, *args, **kwargs):   #__call__写在类中,该类的实例就可调用

print(5)

A()()   #先实例化再调用,等价于a = A();a()

a = A()

a()

a(4,5,6)

输出:

5

5

5

例:

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)

print(p())

输出:

<__main__.Point object at 0x7fbc9e10c710>

Point(4,5)

例:

class Adder:

def __call__(self, *args):

ret = 0

  for x in args:

ret += x

self.ret = ret

return ret

adder = Adder()

print(adder(4,5,6))

print(adder.ret)

输出:

15

15

习题:

定义一个fibonacci数列的类,方便调用,计算第n项;

使用类来实现fibonacci数列,可缓存数据,便于检索;

方1:

class Fib:

def __init__(self):

self.items = [0,1,1]

def __call__(self, index):

if index < len(self.items):

return self.items

# return self.items[index]

if index < 0:

raise IndexError('wrong index')

for i in range(3,index+1):

self.items.append(self.items[i-1] + self.items[i-2])

return self.items

# return self.items[index]

print(Fib()(8))

输出:

[0, 1, 1, 2, 3, 5, 8, 13, 21]

方2:

class Fib:

def __init__(self):

self.items = [0,1,1]

def __call__(self,index):

return self[index]

def __iter__(self):

return iter(self.items)

def __len__(self):

return len(self.items)

def __getitem__(self, index):

if index < len(self.items):

return self.items[index]

if index < 0:

raise IndexError('wrong index')

for i in range(len(self),index+1):   #使用len(self),要加__len__

self.items.append(self.items[i-2] + self.items[i-1])

   return self.items[index]

def __str__(self):

return str(self.items)

__repr__ = __str__

fib = Fib()

print(fib(8),len(fib))

for x in fib:

print(x)

print(fib[8],fib[7])

print(fib[-8])

输出:

21 9

0

1

1

2

3

5

8

13

21

21 13

1

另外有需要云服务器可以了解下创新互联cdcxhl.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。


本文名称:30面向对象5_运算符重载-容器相关方法-可调用对象-创新互联
路径分享:http://www.cdkjz.cn/article/poiee.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

大客户专线   成都:13518219792   座机:028-86922220