python第10次习题

一、集合(set)元素去重的判断依据是什么

1、计算的哈希值一致(前提)
2、内容一致;

在满足计算的哈希值一致的前提下,内容一致则会进行去重;

a = (1,2,3)
b = (1,2,3)
s1 = {a,b}
print(hash(a),hash(b))		#---->2528502973977326415 2528502973977326415
print(a == b)				#---->True
print(a is b)				#---->False
print(id(a),id(b))			#---->2200332504520 2200332504664
print(s1)					#---->{(1, 2, 3)}

#1、比较哈希值,a,b的哈希值一样;(满足前提)
#2、比较内容a == b,返回True,内容一致;(满足第二个条件)
#3、a is b,比较的是内存地址;
#	(内存中由两个对象,标识符是a,b,他们的内存地址不一致)
#4、这个比较同时满足了两个条件:哈希值一致、内容一致,在集合中去重;
class Person:
    def __init__(self,name):
        self.name = name

    def __hash__(self):
        return 100

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

    def __repr__(self):
        return "<{} {}>".format(self.__class__,self.name)

    __str__ = __repr__

t1 = Person('zzh')
t2 = Person('zhy')

print(hash(t1),hash(t2))	#---->100 100
print(t1 == t2)				#---->使用的是__eq__方法,比较的是self.name,一致
print(t1 is t2)				#---->比较的是内存地址,这是两个不同的实例,内存地址不一致
print(id(t1),id(t2))		#---->两个实例的内存地址
print({t1,t2})				#---->{<<class '__main__.Person'> zhy>, <<class '__main__.Person'> zzh>}不进行去重

二、总结本周视频讲解魔术方法的作用及什么情况会执行到该方法;

实例构造

__new__

实例话的两个阶段:
1、__new__构造实例;(需要构造完成实例以后才能初始化)
2、__init__初始化(属性赋值);
class A:
    def __new__(cls, *args, **kwargs):
        #return super(A,cls).__new__(cls)
		return object.__new__(cls)
		
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def show(self):
        return self.x,self.y

t = A(4,5)
print(t.show())

#1、通过__new__方法构造了一个实例;
	#将当前构造方法交给父类进行构造,返回一个实例;(object中__new__是staticmethod)
	
#2、通过__init__方法为实例属性赋值;

可视化:

用于对实例的打印输出:
__str__
__repr__
class Person:
    def __init__(self,name):
        self.name = name

    def __showname(self):
        return self.name

    def __str__(self):
        return self.__showname()

    def __repr__(self):
        return self.__showname()

t = Person('tom')
print(t)
print([t])

#1、__str__直接作用会调用该方法,比如print(t)、str(t)、"{}".format(t)这种情况下;
#2、__repr__间接调用会调用该方法,比如print({t}),print([t]),套到一个容器里头(tuple例外);
#3、如果没有__str__,直接、间接调用都用__repr__
#4、如果没有__repr__,间接调用会调到object中定义__repr__方法,返回的是object定义的格式;

bool的计算与len

__bool__
__len__
class PersonalInformation:
    def __init__(self):
        self.lst = []

    def setinformation(self,*args):
        for i in args:
            self.lst.append(i)

    def __repr__(self):
        return "<personal information: {}>".format(self.lst)

    __str__ = __repr__

    def __bool__(self):
        return True

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

t = PersonalInformation()
print(t)

if bool(t):
    t.setinformation('zhangzhonghao',27,'manle')

print(t)


#1、将PersonalInformation类实例化,创建一个空列表;
#2、打印空列表
#3、当bool(t)返回为True,则调实例setinformation方法,为列表注入参数;
#4、打印注入参数以后的列表;
#5、如果说没有__bool__方法,则会bool函数中注入len(t)--->bool(len(t));

运算符重载

__eq__
__gt__
__ge__
__lt__
__le__
__add__
__iadd__
__sub__
__isub__

在这里插入图片描述

class Person:
    def __init__(self,name,age,height):
        self.name = name
        self.age = age
        self.height = height

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

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

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

    def __repr__(self):
        return "<Person name:{} age:{} height:{}>".format(self.name,self.age,self.height)

    __str__ = __repr__

    def __add__(self, other):
        return self.age + other.age

    def __sub__(self, other):
        return self.age - other.age

    def __iadd__(self, other):
        self.age += other.age
        return __class__(self.name,self.age,self.height)

    def __isub__(self, other):
        self.age -= other.age

#实例化,注入属性
zzh = Person('zhangzhonghao',27,171)
km = Person('km',24,160)

#调__repr__打印属性内容
print(zzh)
print(km)

#比较属性
print(zzh > km)
print(zzh < km)

#属性重新赋值,return self 则就地修改当前实例
#return __class__(self.name,self.age,self.height)则构造新实例
zzh += km
print(zzh)

容器化

在这里插入图片描述

__missing__,用于字典,在一个字典的子类实例中,用key去查找value,keyError时会返回__missing__方法中return的值;
class Dic(dict):
    def __init__(self):
        super(Dic, self).__init__(self)

    def additems(self,**kwargs):
        self.update(kwargs)

    def __missing__(self, key):
        return '666'



t = Dic()
t.additems(a =1 ,b =2 ,c =3)
print(t['d'])
print(t)

容器化实践:
需求:构建一个列表实例,能够实现:
1、实例化; t = ShoppingCar()
2、该实例能够添加、删除元素;t.additems(‘a’)
3、能够使用’+’,’-'来添加删除元素;t.subaddtems(‘b’)
4、在删除元素时如果超出索引则提示index out of range,什么都不做,只是提示,记录日志;
5、能够使用index查找元素,索引则提示index out of range,什么都不做,只是提示,记录日志;
6、能够使用index去修改元素内容,正索引超界则append,负索引超界则insert,在索引范围内则正常查询;t[-100] = 100, t[200] = 200,t[1] = 666
7、能够打印实例、能够迭代实例、能够查看实例长度;

import logging
ValueErr = logging.getLogger('ValueErr')
IndexErr = logging.getLogger('IndexErr')
ValueErr.setLevel(20)
IndexErr.setLevel(20)
h1 = logging.StreamHandler()
h2 = logging.FileHandler('F:/t1.log')
ValueErr.addHandler(h1)
ValueErr.addHandler(h2)
IndexErr.addHandler(h1)
IndexErr.addHandler(h2)
f1 = logging.Formatter('%(levelname)s %(asctime)s %(name)s'
                       '<%(message)s>\t[error file num:%(lineno)s]'
                       '\t[%(pathname)s]')
h1.setFormatter(f1)
h2.setFormatter(f1)

class ShoopingCar:
    def __init__(self):
        self.lst = []

    def additems(self,item):
        return self.__add__(item)

    def subitems(self,item):
        return self.__sub__(item)

    def __add__(self, item):
        self.lst.append(item)
        return self

    def __sub__(self, item):
        try:
            if item in self.lst:
                self.lst.remove(item)
                return self
            else:
                raise ValueError()

        except ValueError:
            ValueErr.info("do noting %%item is not in {}".format(self.__class__.__name__))

    def __getitem__(self, index):
        try:
            if index <= len(self.lst) -1  and index >= -len(self.lst) +1:
                return self.lst[index]
            else:
                raise IndexError()
        except IndexError:
            IndexErr.info("do noting %%Index is out of range")

    def __setitem__(self, index, value):
        if index > len(self.lst) - 1:
            self.lst.append(value)
        elif  index < -len(self.lst) + 1:
            self.lst.insert(0,value)
        else:
            self.lst[index] = value


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

    def __iter__(self):
        return iter(self.lst)

    def __repr__(self):
        return "{}".format(self.lst)

    def __contains__(self, item):
        if item in self.lst:
            return True
        else:
            return False

    __str__ = __repr__

t = ShoopingCar()
t + 'a' + 'b' + 'c' + 'd'
print(t)
t[100]
t - 'z'
t[-100] = 100
t[200] = 200
print(t)

可调用对象

定义一个类,将该类实例化,这个实例能够像函数一样调用;
__call__
class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def add(self):
        return self.x + self.y

    def __call__(self, *args, **kwargs):
        return self.add()

t = Point(4,5)
print(t())

上下文管理
如果有上下文管理,则函数的执行流程为:

__init__ -----> __enter__ ----> with里面的语句块 ----> __exit__ 
上下文管理类似于try ..... finally语句,__exit__中的内容不管有没有出现异常,一定会执行;

__enter__:调用之前增强
__exit__:调用之后增强

类似于装饰器,函数执行之前需要干什么,执行完以后需要干什么;

import datetime
import time

class A:
    def __init__(self):
        pass

    def __enter__(self):
        self.start = datetime.datetime.now()

    def __exit__(self, exc_type, exc_val, exc_tb):
        delta = datetime.datetime.now() - self.start
        print(delta)


def add(x, y):
    time.sleep(2)
    print(x + y)


t = A()
with t as t1:  # 等价于 f = t__enter__()
    add(1, 3)

反射

在程序被加载到内存中执行以后,能够反射出类型的信息;

内建函数:
getattr:用变量名称去找实例属性,写入的name必须为str;----> 等价于t.a
setattr:用变量名称去动态添加实例属性;---->等价于t.x = 100
hasattr:使用变量名称去查看实例属性是否存在,返回bool;---->等价于
class A:
    def __init__(self,a,b,c):
        self.a = a
        self.b = b
        self.c = c

t = A(4,5,6)
print(t.a)					#---->等价于 getattr(t,'a')
setattr(t,'a',100)			#---->等价于 t.a = 100
print(getattr(t,'a'))
print(hasattr(t,'z'))
魔术方法:
__getattr__:如果提供了该方法,在AttributeError时,返回的值为该方法中return的值;
__setattr__:拦截实例属性赋值,修改等,;instance.x = 100或者setattr(instance,'x',100)这种方式时,会调用到__setattr__;
__delattr__:删除实例属性;del instance.x这种方式会调用到__delattr__;需要直接操作字典,不能使用delattr(self,item)会出现递归;
__getattribute__:属性访问第一站,拦截了实例调属性;隐藏实例的__dict__
class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __getattr__(self, item):
        return 10010

    def __setattr__(self, key, value):					#拦截属性的赋值、修改
    	print('我拦截了__init__属性赋值干的活')
        #super(Point, self).__setattr__(self)
        self.__dict__[key] = value

    def __delattr__(self, item):
        super(Point, self).__delattr__(item)
        #self.__dict__.pop(item)

    def __repr__(self):
        return "<{} {} {}>".format(self.__class__.__name__,self.x,self.y)

t = Point(4,5)		#实例化传入参数 4,5
print(t.z)			#打印实例属性z,抛出AttributeError,调__getattr__方法;
t.x = 'A'			#实例属性重新赋值
del t.x				#删除实例属性,调__delattr__方法;
print(t)			#打印实例:<Point 10010 5>,由于x属性被删除,打印时报AttributeError,调__getattr__方法,返回10010;
__getattribute__
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __getattribute__(self, item):  # 拦截了实例调属性;隐藏实例的__dict__;
        print('我是第一站,我拦截了你调用属性,你调用的属性都是我的return值')
        return 666
#        return super().__getattribute__(item)


t = Point(100, 200)		
print(t.x)					---->先打印内容,在返回666
print(t.__dict__)			---->打印内容,实例字典内容为666

当实例去调用属性时查找顺序为

1、__getattribute__()里面return 的值;
MRO
2、实例字典
3、类字典
4、父类字典
5、__getattr__()定义的return 的值;

三、结合本周所学内容,实现如下类:

   class Ob:
     pass
   执行以下操作:
   a = Ob('tom')
   b = Ob('tom')
   print('a: ', a)
   a[0] = 'a'
   print('a:', a)
   a * 3
   print('len: ', len(a))
   del a[1]
   print('a: ', a)
   print('set: ', {a, b})
   其输出如下:
   a: ['1', '2']
   a: ['a', '2']
   len:  6
   a: ['a', 'a', '2', 'a', '2']
   set: {<Ob name=tom items=['a', 'a', '2', 'a', '2']>}
class Ob:
    def __init__(self,name):
        self.name = name
        self.lst = [1,2]

    def __str__(self):
        return "{}".format(self.lst)

    def __repr__(self):
        return "<object name={},items={}>".format(self.name,self.lst)

    def __setitem__(self, key, value):
        self.lst[key] = value

    def __mul__(self, nums):
        self.lst *= nums

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

    def __delattr__(self, item):
        self.lst.remove(item)

    def __delitem__(self, value):
        self.lst.pop(value)

    def __hash__(self):
        return 100

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

a = Ob('tom')
b = Ob('tom')
print('a: ', a)
a[0] = 'a'
print('a:', a)
a * 3
print('len: ', len(a))
del a[1]
print('a: ', a)
print('set: ', {a, b})

输出:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值