面向对象-内置函数和内置方法
python内置函数
isinstance(obj,class)
判断一个对象是否是已知的类型,类似type()
isinstance语法:isinstance(object,classinfo)
- object 是实例/对象
- classinfo 可以是直接或间接类名,基本类型或者由他们组成的元组
返回值
如果对象的类型与classinfo相同,返回bool值True,否则返回False
isinstance 与type的区别:
- type()不会认为子类是一种父类类型,不考虑继承关系
- isinstance() 会认为子类是一种父类类型,考虑继承关系,
如果要判断两个类型是否相同的时候尽量用isinstance()
示例1:
a = [1,2,3] print(isinstance(a,list))
输出: True
示例2:
class A(object):pass class B(A):pass b=A() print(isinstance(b,A)) # 返回True b 是 A 的对象 print(type(b) is B) # 返回False b不是B类的对象 print(type(b) is A) #type 在这里是检测对象是不是类的对象/实例
issubclass( )
判断两个类是否有继承关系,,如果真的有继承关系,那就返回bool值True/False
class A(object):pass class B(A):pass print(issubclass(B,A)) # True B类是A类的子类 print(issubclass(A,B)) # False
内置方法
什么是内置方法?
内置方法也叫双下方法,魔术方法,它们在python中处处皆是,它们是一些可以让你对类添加"魔法"的特殊方法,经常都是双下划线包围来命名的比如(__init__,__str__)等等,到现在还是没有很好的办法来解释它们.
内置方法的特点
一定有某一个语法或者一种写法自动触发这个方法.
常见常用的内置方法
最常见的__init__ 是个初始化方法,类的初始化方法, 然而当我们执行 a =class()的时候,__init__并不是 第一个被调用的方法,事实上__new__第一个被调用,这个方法才真正的创建了实例/对象,当这个对象生命周期结束的时候,这时候__del__方法会被调用.看到这样的联系,让我们进一步了解他们的特性!
__new__ 也叫构造方法,__(cls,[...)__ 它提供了一个实例化对象的时候所需要的内存空间 例如--->创建空间
首先说说设计模式中的单例模式, __new__是对象实例化的时候第一个被调用的方法,它只取cls也就是类的参数,把其他参数传给__init__..
单例模式示例1
class Teacher2: flag = None #静态属性为空 def __new__(cls, *args, **kwargs): if cls.flag is None: #执行判断 cls.flag 也就是Teacher2类的静态属性为空的情况下 cls.flag = object.__new__(cls) #这句话直走一次 #Teacher2继承的父类 object.__new__(cls)开辟/构建的空间地址赋予Teacher2类的静态属性 print(cls.flag) return cls.flag #类的静态属性得到的空间地址赋值Sheldon2 Sheldon2 = Teacher2() ssa = Teacher2() #当ssa执行实例化的时候,flag 已经不等于None,而等于一个空间地址, 不走if判断,直接把原先的空间地址赋值给ssa
单例模式示例2
class Teacher: flag = None def __new__(cls,*args,**kwargs): # if cls.flag is None: cls.flag = object.__new__(cls) return cls.flag def __init__(self,name): self.name = name Sheldon = Teacher('Sheldon') Penny = Teacher('Penny') print('Sheldon.name') #输出 Sheldon print('Penny.name') #输出 Penny print('Sheldon.name') ##输出 Penny
__init__ (self[...) 类初始化方法 实例化
它获取任何传给构造器的参数,(例如Sheldon = Teacher('Sheldon') __init__ 就会接收到参数Sheldon. __init__在python类的定义中用的最多
__del__ (self) 析构方法
__del__ 是对象的销毁器,它并不是实现了语句中 del Sheldon 因此它并不等于 Sheldon.__del__(), 而是定义了对象的垃圾回收时的行为,当对象需要销毁时做的一些处理的时候,这个方法会用到,
class Teacher: def __init__(self,name): self.name = name def __del__(self): print('执行删除动作') Sheldon = Teacher('Sheldon') print('11111') # 输出顺序 11111 ---> 执行删除动作 ---> 删除Sheldon del Sheldon # 执行del 对象的时候触发了__del__ ,在真正删除Sheldon对象前,执行方法__del__ # 如果我们不删除 Sheldon ,那么程序的执行过程中或最后,垃圾回收机制会替你执行del Sheldon # del Sheldon ---> 执行__del--->删除Sheldon
__call__(self[args...) 可调用的对象
你可能已经知道了,在Python中,函数是一等的对象。这意味着它们可以像其他任何对象一样被传递到函数和方法中,这是一个十分强大的特性。
允许类的一个实例像函数那样被调用。本质上这代表了 a() 和 a.__call__() 是相同的。注意 __call__ 可以有多个参数,这代表你可以像定义其他任何函数一样,定义 __call__ ,喜欢用多少参数就用多少。
class Student: def __init__(self,name,sex): self.name = name self.sex =sex def __call__(self, *args, **kwargs): print('执行调用了') Sheldon = Student('Sheldon','male') # callable() 查看某个变量是否能被调用 #callable(变量) 返回True 意味着 变量()--->调用 print(callable(Student)) #类可以被调用 print(callable(Sheldon)) # 对象可以被调用 Sheldon() #执行__call__方法
__str__ (self) 定义类的实例调用str()的行为
能在打印对象的时,不输出无用的内存地址,输出你需要的格式化字符串
常用写法: 1. print(对象) 2.str(对象) 3.'%s'%对象
class Course: def __init__(self,name,price,period,teacher): self.name = name self.price = price self.period = period self.teacher = teacher def __str__(self): #必须有一个返回值,必须返回一个str类型 return '%s,%s,%s,%s'%(self.name,self.price,self.period,self.teacher) course_lst = [] python = Course('python',1111,'12','Sheldon') linux = Course('linux',2222,'12','Lins') print(python) # 写法1 print(str(python)) # 写法2 print('课程展示 : %s'%python) # 写法3 course_lst.append(python) course_lst.append(linux) for course in course_lst: print(course) # 直接展示所有课程
__repr__ (self) 是__str__(self) 的备胎,(有str就调用str,没有str调用repr)
定义对类的实例调用repr()时的行为,str()和repr()最大的区别在于'目标用户',repr()的作用是产生机器可读的输出,(大部分情况下,输出可作为python有效代码),而str()则产生人类可读输出
示例1
class Course: def __init__(self,name,price,period,teacher): self.name = name self.price = price self.period = period self.teacher = teacher def __repr__(self): # 必须有返回值,必须返回一个str类型 return 'repr --> : %s,%s,%s,%s' % (self.name, self.price, self.period, self.teacher) python = Course('python',1111,'12','Sheldon') linux = Course('linux',2222,'12','Lins') print('%r'%python) print('%s'%python) print(str(python)) print(repr(python)) #全部输出 repr可以输出str方法 repr --> : python,1111,12,Sheldon repr --> : python,1111,12,Sheldon repr --> : python,1111,12,Sheldon repr --> : python,1111,12,Sheldon
示例2
class Course: def __init__(self,name,price,period,teacher): self.name = name self.price = price self.period = period self.teacher = teacher # def __repr__(self): # 必须有返回值,必须返回一个str类型 # return 'repr --> : %s,%s,%s,%s' % (self.name, self.price, self.period, self.teacher) python = Course('python',1111,'12','Sheldon') linux = Course('linux',2222,'12','Lins') print('%r'%python) print('%s'%python) print(str(python)) print(repr(python)) #输出 str只能输出str方法,无法输出repr方法 <__main__.Course object at 0x00000000027E15C0> str --> : python,1111,12,Sheldon str --> : python,1111,12,Sheldon <__main__.Course object at 0x00000000027E15C0>
__unicode__(self) 不常用,但是跟__str__ ,__repr__
定义对类的实例调用 unicode() 时的行为。 unicode() 和 str() 很像,只是它返回unicode字符串。注意,如果调用者试图调用 str() 而你的类只实现了 __unicode__() ,那么类将不能正常工作。所有你应该总是定义 __str__() .
class Course: def __init__(self,name,price,period,teacher): self.name = name self.price = price self.period = period self.teacher = teacher def __unicode__(self): # 必须有返回值,必须返回一个str类型 return 'unicode --> : %s,%s,%s,%s'%(self.name,self.price,self.period,self.teacher) python = Course('python',1111,'12','Sheldon') linux = Course('linux',2222,'12','Lins') print('%r'%python) print('%s'%python) print(str(python)) print(repr(python)) #全部输出 unicode可以输出str,repr方法,但是是unicode字符串类型 <__main__.Course object at 0x00000000027C15C0> <__main__.Course object at 0x00000000027C15C0> <__main__.Course object at 0x00000000027C15C0> <__main__.Course object at 0x00000000027C15C0>
容器背后的魔法
item系列方法
-
__getitem__(self,item) 表达方式 :obj.['xxx'] == >obj.xxx
定义对容器中某一项的使用self[key] 的方式进行读取操作时的行为。这也是可变和不可变容器类型都需要实现的一个方法。它应该在键的类型错误式产生 TypeError 异常,同时在没有与键值相匹配的内容时产生 KeyError 异常。
-
__setitem__(self,key,value) 表达方式:obj['xxx'] =yyy ---> obj.xxx=yyy
定义对容器中某一项使用 self[key] 的方式进行赋值操作时的行为。它是可变容器类型必须实现的一个方法,同样应该在合适的时候产生 KeyError 和 TypeError 异常。 __iter__(self, key) 它应该返回当前容器的一个迭代器。迭代器以一连串内容的形式返回,最常见的是使用 iter() 函数调用,以及在类似 for x in container: 的循环中被调用。迭代器是他们自己的对象,需要定义 __iter__ 方法并在其中返回自己。
-
__delitem__(self,key) del obj['xxx'] ===> del obj.xxx
定义对容器中某一项使用 self[key] 的方式进行删除操作时的行为。
class Course: def __init__(self,name,price,period,teacher): self.name = name self.price = price self.period = period self.teacher = teacher def __len__(self): return len(self.__dict__) def __getitem__(self, item): return self.__dict__[item] def __setitem__(self, key, value): self.__dict__[key] = value def __delitem__(self, key): self.__dict__.pop(key) python = Course('python',1111,'12','Sheldon') linux = Course('linux',2222,'12','Lins') print(len(python)) # 输出 4 print(python['name']) # 输出 python print(python['price']) # 输出 1111 python['name'] = 'python.2.0' # 针对python.name 进行修改 print(python.name) # python.2.0 发现已经被修改 del python['name'] # 执行删除python.name 操作 print(python.__dict__) # {'price': 1111, 'period': '12', 'teacher': 'Sheldon'} 查看 python对象 发现 name被删除了
总结,有一些内置函数/模块要想正确的使用它们,那么必须按照它规定的语法来实现
__len__ (self) 很常用的方法 表现方式: object.__len__()
返回容器的长度,可变和不可变类型都需要实现。
class Ruler: def __init__(self,price,length,precision): self.price = price self.length = length self.precision = precision def __len__(self): return self.length ruler = Ruler(3,20,0.1) print(len(ruler)) #调用__len__方法后拿到长度 20
比较操作符系列 返回bool值
__cmp__(self,other)
__cmp__ 是所有比较魔法方法中最基础的一个,它实际上定义了所有比较操作符的行为(<,==,!=,等等),但是它可能不能按照你需要的方式工作(例如,判断一个实例和另一个实例是否相等采用一套标准,而与判断一个实例是否大于另一实例采用另一套)。 __cmp__ 应该在 self < other 时返回一个负整数,在 self == other 时返回False,在 self > other 时返回正整数。最好只定义你所需要的比较形式,而不是一次定义全部。 如果你需要实现所有的比较形式,而且它们的判断标准类似,那么 __cmp__ 是一个很好的方法,可以减少代码重复,让代码更简洁
-
__eq__(self,other) 定义等于操作符 == 的行为
class Scientist: def __init__(self,name,age): self.name = name self.age = age def __eq__(self, other): if self.name == other.name and self.age == other.name: return True return False name1 = Scientist('Sheldon',29) name2 = Scientist('Sheldon',29) # print(name1 == name2) # print(name1 is name2) print(name1.__eq__(name2)) #这三种方法输出都False, name1 和name2 实例化后得到的内存地址不同,所以并不相同
-
__ne__(self,other) 定义不等于 != 行为
-
__lt__(self,other) 定义小于 < 行为
-
__gt__(self,other) 定义大于 > 行为
-
__le__(self,other) 定于小于等于 <= 行为
-
__ge__(self,other) 定于大于等于 >= 行为
...