ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Day 17:Python 对象的相等性比较

2021-07-05 14:33:21  阅读:152  来源: 互联网

标签:__ name 17 Python self print male sexual Day


掌握一些判断对象相等时用的关键字,Python 中,对象相等性比较相关关键字包括 is、in,比较运算符有 ==

is 关键字判断标识号是否相等

is 比较的是两个对象的标识号是否相等,标识号的获取用id()函数。

a=[1,2,3,4,5]
b=[1,2,3,4,5]
print(id(a))
print(id(b))
a is b

output:
7696573018440
7696556316232
False

由于这两个list实例化与不同的内存地址,标识号不相等,那么两个空list实例,会不会相等呢?实则不然。

c,d = [], []
c is d

output:

False

对于序列型、字典型、集合型对象,只有当一个对象实例指向另一个对象实例时候,is的比较结果才返回true.

a,b = [1,2,3],{'a':111,'2':222}
print(a is b)
a = b
print(a,b,a is b)

output:
False
{'a': 111, '2': 222} {'a': 111, '2': 222} True

但是对于数值类型,结果可能会不太一样,看编译器。

 a = 1
 b = 1
 print(a is b)
 c = 65535
 d = 65535
 print(c is d)

output:
True

Python 解释器,对位于区间 [-5,256] 内的小整数,会进行缓存,不在该范围内的不会缓存,所以才出现上面的现象。

还需要注意的是,python中有一个None对象,具有唯一,不变的标识号(当前环境下)

print(id(None))
a = None
print(a is None) #判断某个对象是否为None
print(id(None))

output:
17106540000
True
17106540000

in 关键字用于成员检测

  • 如果元素 i 是 s 的成员,则 i in s 为 True;
  • 若不是 s 的成员,则返回 False,也就是 i not in s 为 True。
  • python内置的序列类型、字典类型和集合类型,都支持 in 操作。
  • 字典使用,in 操作判断 i 是否是字典的键。
  • 如果是字符串s,判断子串i的操作,也就是 s.find(i) 返回大于 - 的值。
  • 对于自定义类型,判断是否位于序列类型中,需要重写序列类型的__contains__。
# 根据 Student 类的 name 属性(所以要重写__contains__),判断某 Student 是否在 Students 序列对象中。

# 自定义 Student 类,无特殊之处
class Student():
    def __init__(self,name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self,val):
        self._name = val
# Students 类继承 list,并重写 __contains__ 方法
class Students(list):
        def __contains__(self,_):
            for s in self:
                if s.name ==_.name:
                    return True
            return False

s1 = Student('xiaoming')
s2 = Student('xiaohong')
a = Students()
a.extend([s1,s2])#list方法
s3 = Student('xiaoming')
print(s3 in a) # True
s4 = Student('xiaoli')
print(s4 in a) # False

output:
True
False

== 关键字判断值是否相等

  • 对于数值型、字符串、列表、字典、集合,默认只要元素值相等,== 比较结果是 True。
  • 对于自定义类型,当所有属性取值完全相同的两个实例,判断 == 时,返回 False。
  • 一般如果两个对象的所有属性相同时,尽管他们的名字不同,那么他们还是相等的。所以就是需要判断所有属性相同与否的方法。

例子:

 

 

 

class Student():
    def __init__(self,name,age):
        self._name = name
        self._age = age

    @property
    def name(self):
        return self._name    
    @name.setter
    def name(self,val):
        self._name = val

    @property
    def age(self):
        return self._age    
    @age.setter
    def age(self,val):
        self._age = val
   # 重写方法 __eq__,使用 __dict__ 获取实例的所有属性。
    def __eq__(self,val):
        print(self.__dict__)
        return self.__dict__ == val.__dict__
    
a = []
xiaoming = Student('xiaoming',29)
if xiaoming not in a:
    a.append(xiaoming)
    
xiaohong = Student('xiaohong',30)
if xiaohong not in a:
    a.append(xiaohong)
    
xiaoming2 = Student('xiaoming',29)
if xiaoming2 == xiaoming:
    print('对象完全一致,相等')
    
if xiaoming2 not in a:
    a.append(xiaoming2)

print(len(a))

output:
{'_name': 'xiaohong', '_age': 30}
{'_name': 'xiaoming', '_age': 29}
对象完全一致,相等
{'_name': 'xiaoming', '_age': 29}
2

Bonus - @property说明

对于类的变量,有私有和全局,看例子

class Menber(object):
    def __init__(self, name, sexual):
        self.__name = name
        self.__sexual = sexual

    def get_sexual_fun(self):
         return self.__sexual

    def set_sexual_fun(self, value):
        if value not in ['male','female']:
            raise ValueError('sexual must be male or female.')
        self.__sexual = value

    def print_info(self):
        print('%s: %s' % (self.__name, self.__sexual))

p = Menber('linda','female')
p.__sexual = 'male'
print(p.__sexual) # male
print(p.get_sexual_fun()) # female
p.print_info()
p.set_sexual_fun('male')
print(p.get_sexual_fun()) # male
p.print_info()


output:
male
female
linda: female
male
linda: male
 
 

使用一个set来设置变量,使用一个get来获取变量,就可以达到检查参数的目的。

还有重要的一点,表面上在外部看似把sexual设置成了另一个值,但其实并没有改变内部的值,

这个p.__sexual = 'male'和内部的self.__sexual = 'female'压根就是两个东西。

内部的_sexual 变量已经被Python解释器自动改成了_Person_sexual,而外部代码给p新增了一个_sexual变量。 所以调用get_sexual_fun输出的是初始值 female.

而set_sexual_fun通过class内部改变了_sexual变量值,所以最终输出 linda: male

  现在,只是改私有变量为全局变量,看效果:

class Menber(object):
    def __init__(self, name, sexual):
        self._name = name
        self._sexual = sexual

    def get_sexual_fun(self):
         return self._sexual

    def set_sexual_fun(self, value):
        if value not in ['male','female']:
            raise ValueError('sexual must be male or female.')
        self._sexual = value

    def print_info(self):
        print('%s: %s' % (self._name, self._sexual))

p = Menber('linda','female')
p._sexual = 'male'
print(p._sexual) # male
print(p.get_sexual_fun()) # female
p.print_info()
p.set_sexual_fun('male')
print(p.get_sexual_fun()) # male
p.print_info()

output:
male
male
linda: male
male
linda: male

因为此时_sexual是全局变量,外部直接影响到类内部的更新值

那么怎样才能避免这种繁琐的方式呢?

有没有可以用类似属性这样简单的方式来访问类的变量呢?

答:装饰器@property

class Menber(object):
    def __init__(self, name, sexual):
        self.__name = name
        self.__sexual = sexual

    @property
    def get_sexual_fun(self):
         return self.__sexual

    @get_sexual_fun.setter # get_sexual_fun
    def set_sexual_fun(self, value):
        if value not in ['male','female']:
            raise ValueError('sexual must be male or female.')
        self.__sexual = value

    def print_info(self):
        print('%s: %s' % (self.__name, self.__sexual))

p = Menber('linda','female')
p.__sexual = 'male'
print(p.__sexual) # male
print(p.get_sexual_fun) # female   这里不能带()  如果带()要报错

p.set_sexual_fun = 'male'
print(p.get_sexual_fun) # male
p.print_info()

output:
male
female #尽管没有改变内部的值
male # 但是这样的设置使得能够检查参数
linda: male

这样,既能检查参数,又可以用类似属性这样简单的方式来访问类的变量。

@property本身又创建了另一个装饰器@get_sexual_fun.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作:

class Menber(object):
    def __init__(self, name, sexual):
        self.__name = name
        self.__sexual = sexual

    @property
    def get_sexual_fun(self):
         return self.__sexual

    @get_sexual_fun.setter # get_sexual_fun
    def set_sexual_fun(self, value):
        if value not in ['male','female']:
            raise ValueError('sexual must be male or female.')
        self.__sexual = value

    def print_info(self):
        print('%s: %s' % (self.__name, self.__sexual))
        
q = Menber('david', 'male')
q.__sexual 

output:
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-64-116170232977> in <module>()
     18 
     19 q = Menber('david', 'male')
---> 20 q.__sexual

AttributeError: 'Menber' object has no attribute '__sexual'

意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的

总的来说:使用 property 工具,它把方法包装成属性,让方法可以以属性的形式被访问和调用。

  • 被 @property 装饰的方法是获取属性值的方法,被装饰方法的名字会被用做 属性名。
  • 被 @属性名.setter 装饰的方法是设置属性值的方法。
  • 被 @属性名.deleter 装饰的方法是删除属性值的方法。

标签:__,name,17,Python,self,print,male,sexual,Day
来源: https://www.cnblogs.com/PiaYie/p/14972208.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有