面向对象进阶、反射 isinstance和issubclass del__ __new__构造方法 item系列 __call__
isinstance和issubclass
- 反射
- setattr
- delattr
- getattr
- hasattr
- __str__和__repr__
- __del__
- item系列
- __getitem__
- __setitem__
- __delitem__
- __new__
- __call__
- __len__
- __hash__
- __eq__
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
#对象与类之间的关系
#对象与类之间的关系 #判断第一个参数是否是第二个参数的实例 #身份运算 2 == 3 # 值是否相等 2 is 3 # 内存地址是否相等 class A:pass#创建一个类 class B(A):pass#B继承A类 class C(B):pass#C继承B类 c = C()#实例化一个C print(isinstance(c,A)) # True包含继承关系的判断 print(type(c) is C) # type只关心创建这个对象的类
issubclass(sub, super)检查sub类是否是 super 类的派生类
#类与类之间的关系
#类与类之间的关系 #issubclass() class A:pass创建一个A类 class B(A):pass#B类继承A类 print(issubclass(A,B))#False不是包含关系 print(issubclass(B,A))#True是包含关系 #第一个参数是疑似子类,第二个参数是疑似父类. #最终结果如果真的是父子类关系,则返回True
反 射
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
hasattr、getattr、setattr、delattr
class Foo:#定义一个类 f = '类的静态变量' def __init__(self,name,age):#定义一个动态属性 self.name=name self.age=age def say_hi(self):#定义一个say_hi方法 print('hi,%s'%self.name)#打印hi,对象 obj=Foo('egon',73) #检测是否含有某属性 print(hasattr(obj,'name'))#检测是否含name属性True print(hasattr(obj,'say_hi'))#检测是否含有say_hi属性True #获取属性 n=getattr(obj,'name')#获取对象的name属性的值 print(n) # 类.静态属性 getattr(类,'静态属性') # 对象.方法 # getattr(对象,'方法')() 直接反射得到一个方法之后调用 # 对象.对象属性 # 应用场景 : 网络编程 从文件中读取信息反映到编程中 func=getattr(obj,'say_hi')#获取对象的方法ip地址 func()#执行函数 print(getattr(obj,'aaaaaaaa','不存在啊')) #找不到就报错 #设置属性 setattr(obj,'sb',True)# 为一个变量增加或者修改一个属性 setattr(obj,'show_name',lambda self:self.name+'sb') print(obj.__dict__)#打印obj内的字典 print(obj.show_name(obj))#打印更改后的属性 #删除属性 delattr(obj,'age')#删除一个变量中的属性或者方法 delattr(obj,'show_name') delattr(obj,'show_name111')#不存在,则报错 print(obj.__dict__)#打印obj的字典 # hasattr 判断某一个 变量 是否能够.调用一个名字,返回True或者False # getattr 直接获取一个变量中的名字的值 # setattr 为一个变量增加或者修改一个属性 # delattr 删除一个变量中的属性或者方法
d = {'k':'v'} #d.keys()
print(getattr(d,'keys')())
f = open() # f文件操作对象
f.read() # 文件对象.read方法
a.b 模块名.函数名 import my_moudle#引入一个模块 print(my_moudle.money)#打印my_money类的_money属性 print(getattr(my_moudle,'money'))#得到my_moudle的money属性 getattr(my_moudle,'qqxing')()#得到并运行qqxing函数
包
import 包名 ---> 包内的__init__文件
反射类中的名字
# getattr(类名,'静态属性')
# getattr(类名,'类方法')()
# getattr(类名,'静态方法')()
反射对象中的名字
# getattr(对象名,'对象属性')
# getattr(对象名,'方法名')()
反射模块中的名字
# import 模块名
# getattr(模块名,'模块中的变量')
# getattr(模块名,'模块中的函数')()
# getattr(模块名,'模块中的类名')
反射当前模块中的名字
# import sys
# getattr(sys.modules[__name__],'变量')
# getattr(sys.modules[__name__],'函数')()
# getattr(sys.modules[__name__],'类名')
import sys#引入sys模块 sys.modules[__name__] print(sys.modules[__name__])#<module '__main__' from '/Users/guoyuanjie/Desktop/day27/day27/3.反射.py'> # 所有导入过的模块 # {'字符串数据类型的模块名':模块的内存地址} # {'__main__':当前模块的内存地址}
类中的内置方法 __方法名__
魔术方法 双下方法
内置方法 : 是直接和python的语法隐形相关
len()内置函数 __len__()
hash()哈希函数 __hash__()
str() __str__()
l = [1,2,3,4]
len(l)
class A:#定义一个属性 def __init__(self,name,cls,age,sex):#初始化 self.name = name#name属性 self.cls = cls#cls属性 self.age = age#age属性 self.sex = sex#sex属性 def __eq__(self, other): if self.__dict__ == other.__dict__:return True return True def __len__(self):#__len__方法属性 return len(self.__dict__)#返回一个len(对象的字典的个数) hei = A('小黑','py10期',18,'无')#实例化小黑 hei2 = A('小2黑','py11期',17,'无')#实例化小黑二 def len(obj):#定义一个函数,传入对象 return obj.__len__()#返回一个对象属性 print(len(hei))#打印hei的个数4 print(hei.__dict__)#{'name': '小黑', 'cls': 'py10期', 'age': 18, 'sex': '无'}打印对象hei的字典方法 print(hei2.__dict__)#{'name': '小2黑', 'cls': 'py11期', 'age': 17, 'sex': '无'}打印对象hei2的字典方法 print(hei == hei2) # #True 两个对象就算值是完全相等的,但是仍然内存地址不同 # == 时间上是比较内存地址的 # == 实际上是调用了__eq__方法
format_dict={ 'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型 'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址 'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名 } class School: def __init__(self,name,addr,type):#初始化对象 self.name=name self.addr=addr self.type=type def __format__(self, format_spec):#定义一个__format__方法 return format_spec.format(obj=self)#返回一个 s1=School('oldboy1','北京','私立')#实例化一个北京的学校 print(format(s1,format_dict['tna']))#私立:oldboy1:北京 print(format(s1,format_dict['nat']))# oldboy1-北京-私立 print(format(s1,format_dict['tan']))# 私立/北京/oldboy1 print(format(s1,'tna'))# tna print(format(s1,'tan'))# tan
class School: def __init__(self,name,addr,type): self.name=name self.addr=addr self.type=type def __str__(self): return str(self.__dict__) def __repr__(self): # repr是str的备胎 return 'repr : school的repr对象' s1=School('oldboy1','北京','私立') print(str(s1))#{'name': 'oldboy1', 'addr': '北京', 'type': '私立'} print('%s'%s1)#{'name': 'oldboy1', 'addr': '北京', 'type': '私立'} print(s1)#{'name': 'oldboy1', 'addr': '北京', 'type': '私立'} print(repr(s1))#repr : school的repr对象 print('%r'%s1)#repr : school的repr对象 print('%s'%s1) # str __str__ # %s str 直接打印 内部都是调用了__str__
object __eq__,__str__,__repr__
del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo: def __del__(self): print('执行我啦') f1=Foo() del f1 print('------->') #输出结果 执行我啦 ------->
# 构造方法 创建一个对象的 # 初始化方法 __init__ 给已经创建出来的对象添加属性 # 析构方法 删除一个对象的时候调用的方法 import time class A: def __init__(self): self.f = open('userinfo','a') def consume(self): pass def __del__(self): '''在删除一个对象之前做一些收尾工作''' self.f.close() print('删除一个对象的时候调用我') a = A() time.sleep(1) del a # 删除一个对象的时候,如果内部存在__del__方法, # 那么在删除一个对象之前先执行__del__方法中的代码 print(a)
__new__构造方法
# new一个对象 # object.__new__() class A: def __init__(self):#初始化init方法 print('执行init方法了') def __new__(cls):#函数中先执行new方法 print('执行new方法了') return object.__new__(cls) # 创造对象,将对象返回 a = A()# print(type(a)) print(type(A)) # 先执行__new__方法 创造出一个对象 # 然后把创造出来的对象传递给__init__方法 # 会把self自动的返回,被a接收
元类
有一个元类 在创建类
type() 所有直接用class创建出来的类的元类都是type
class 类名(B,classMeta = 元类名)
class 类名(B,classMeta = type) # 默认
元类 创造 类 所以所有的类的type都是它的元类,默认是type
类 创造 对象 具体创造对象的方法 __new__方法,所有的对象的type都是它对应的类
python中 一切皆对象
变量 都有它属于的数据类型
设计模式
单例模式
一个类 可以被多次实例化 但是同一时间在python的内存中,只能有一个实例
class A: _instance = None#定义一个静态变量 def __init__(self,name):#初始化方法 '''给娃穿衣服''' self.name = name#定义一个动态属性 def __new__(cls, *args, **kwargs):#定义一个new方法 '''生娃的过程''' if not A._instance:#如果没有A._instance A._instance = object.__new__(cls)#类属性等于对象的属性 return A._instance#返回一个类属性 a1 = A('alex') # 第一次实例化的时候创造一个实例 print(a1.name)#alex a2 = A('egon') print(a1.name,a2.name,a1 is a2) # egon egon True
class A: def __init__(self,name): '''给娃穿衣服''' self.name = name def __new__(cls, *args, **kwargs): '''生娃的过程''' if not hasattr(A,'_instance'):#如果没有 A._instance = object.__new__(cls) return A._instance a1 = A('alex') # 第一次实例化的时候创造一个实例 print(a1.name)#alex a2 = A('egon') print(a1.name,a2.name) #egon egon
item系列
__getitem__\__setitem__\__delitem__
class A: def __init__(self,name):#初始化方法 self.name = name#定义一个静态属性 self.age = 81 def __getitem__(self, item):#查看一个对象的的方法 return self.__dict__[item] def __setitem__(self, key, value):#增加和修改一个动态属性 self.__dict__[key] = value def __delitem__(self, key):#删除一个动态属性 del self.__dict__[key] a = A('alex')#实例化 print(a['name']) #alex 对应了类中一个方法的语法#a.name==a['name'] print(a['age']) #81 对应了类中一个方法的语法#a.age==a['age'] # 增加 和 修改一个属性 a['sex'] = '不详'# a.sex = '不详'#增加一个a.sex='不祥' print(a.__dict__)#{'name': 'alex', 'age': 81, 'sex': '不详'} # print(a.sex) # print(a['sex']) a['sex'] = '女'#修改一个对象的动态属性 print(a.__dict__)#{'name': 'alex', 'age': 81, 'sex': '女'} del a['sex']#删除一个a['sex']的属性 print(a.__dict__)#{'name': 'alex', 'age': 81}
__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__ obj() # 执行 __call__
class A: def __call__(self,a): print('执行我了',a) def call(self,b): print('执行我了',b) a = A() a('aaa') # __call__ a.call('bbb')
hash
不可变的数据类型都可以被hash
class A: def __init__(self): self.a = 1 self.b = 2 def __hash__(self):#定义一个魔术方法 print(hash(str(12)))#同一时间字符串12的哈希值#7130726887503445041 return hash(str(self.a)+str(self.b))#同一时间返回一个哈希值'12'#7130726887503445041 a = A() print(hash(a))#返回对象的哈希值
class A:pass # def __hash__(self): # return 1 a = A() b = A() print(hash(a)) # object.__hash__()#同一时间同一个对象的hash值不管调用几次都相同 print(hash(a)) # object.__hash__() print(hash(a)) # object.__hash__() print(hash(a)) # object.__hash__() print(hash(a)) # object.__hash__() print(hash(a)) # object.__hash__() print(hash(a)) # object.__hash__() print(hash(b)) # object.__hash__() # dict的key set的元素 # dic key --> value # dic[key] = value # hash(obj)函数,obj对象对应的类必然内部实现了__hash__方法 # hash的结果就是__hash__方法的返回值 # 且在一次成的执行过程中是不会发生变化的 # 且要想作为字典的key或者作为集合的元素,这个对象对应的类必须实现__hash__方法
数据结构与算法 python 数据结构
python核心编程第二三版 基础
流畅的python 进阶
扑克牌例子
from collections import namedtuple#引用一个collections模块namedtuple可命名元祖 Card = namedtuple('Card',['rank','suit'])#创建一个可命名元祖 # card1 = Card(1,'红桃') class FranchDeck:#创建一个类 ranks = [str(n) for n in range(2,11)] + list('JQKA')#设定大小静态属性 suits = ['红心','方板','梅花','黑桃']#设置花色静态属性 def __init__(self):#初始化一个元祖属性 self._cards = [Card(rank,suit) for rank in FranchDeck.ranks for suit in FranchDeck.suits] def __len__(self):#定义一个len方法 return len(self._cards)# 返回对象的_cards属性的个数 def __getitem__(self, item):#查询方法 return self._cards[item]#返回一个对象属性的所有内容 def __setitem__(self, key, value): self._cards[key] = value deck = FranchDeck() print('**',deck[:]) from random import choice#引入选择模块 print(choice(deck)) # deck对象对应的类中的getitem方法和len方法 from random import shuffle#打乱顺序 shuffle(deck)#打印顺序 print('**',deck[:])
# 金融公司面试题 # 有一个类,对应这个类产生了100个对象 # 每个对象有三个属性 : 姓名 年龄 性别 # 请对这一百个对象进行去重,如果姓名和性别相同,即便年龄不同也是相同的对象 # 问最简便的方法? class Person:#定义一个类 def __init__(self,name,age,sex):#初始化属性 self.name = name#对象的name属性 self.age = age#对象的age属性 self.sex = sex#对象的sex属性 def __hash__(self):#定义哈希方法 return hash('%s%s'%(self.name,self.sex))#返回hash'self.name,self.sex'的值 def __eq__(self, other):#定义一个eq方法 if self.name == other.name and self.sex == other.sex:#如果对象属性等于 return True p_lst = []#定义个空列表 for i in range(100):#打印0到99 p_lst.append(Person('egon',i,'male'))#p_lst列表添加Person('egon',i,'male') p_lst.append(Person('alex',i,'male'))#p_lst列表添加Person('alex',i,'male') p_lst.append(Person('yuan',i,'male'))#p_lst列表添加Person('yuan',i,'male') print(p_lst) print(set(p_lst)) # 报错不可hash 完成了__hash__ # hash是否相等 __hash__ # 值是否相等 __eq__ # 收获1 # 对于一些python当中已经存在的内置函数 内置数据类型 内置模块中的方法 # 都有可能依赖于类中的内置方法 # 收获2 # set方法依赖集合中元素对象的__hash__ __eq__
isinstance和issubclass
- 反射
- setattr
- delattr
- getattr
- hasattr
- __str__和__repr__
- __del__
- item系列
- __getitem__
- __setitem__
- __delitem__
- __new__
- __call__
- __len__
- __hash__
- __eq__
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
#对象与类之间的关系
#对象与类之间的关系 #判断第一个参数是否是第二个参数的实例 #身份运算 2 == 3 # 值是否相等 2 is 3 # 内存地址是否相等 class A:pass#创建一个类 class B(A):pass#B继承A类 class C(B):pass#C继承B类 c = C()#实例化一个C print(isinstance(c,A)) # True包含继承关系的判断 print(type(c) is C) # type只关心创建这个对象的类
issubclass(sub, super)检查sub类是否是 super 类的派生类
#类与类之间的关系
#类与类之间的关系 #issubclass() class A:pass创建一个A类 class B(A):pass#B类继承A类 print(issubclass(A,B))#False不是包含关系 print(issubclass(B,A))#True是包含关系 #第一个参数是疑似子类,第二个参数是疑似父类. #最终结果如果真的是父子类关系,则返回True
反 射
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
hasattr、getattr、setattr、delattr
class Foo:#定义一个类 f = '类的静态变量' def __init__(self,name,age):#定义一个动态属性 self.name=name self.age=age def say_hi(self):#定义一个say_hi方法 print('hi,%s'%self.name)#打印hi,对象 obj=Foo('egon',73) #检测是否含有某属性 print(hasattr(obj,'name'))#检测是否含name属性True print(hasattr(obj,'say_hi'))#检测是否含有say_hi属性True #获取属性 n=getattr(obj,'name')#获取对象的name属性的值 print(n) # 类.静态属性 getattr(类,'静态属性') # 对象.方法 # getattr(对象,'方法')() 直接反射得到一个方法之后调用 # 对象.对象属性 # 应用场景 : 网络编程 从文件中读取信息反映到编程中 func=getattr(obj,'say_hi')#获取对象的方法ip地址 func()#执行函数 print(getattr(obj,'aaaaaaaa','不存在啊')) #找不到就报错 #设置属性 setattr(obj,'sb',True)# 为一个变量增加或者修改一个属性 setattr(obj,'show_name',lambda self:self.name+'sb') print(obj.__dict__)#打印obj内的字典 print(obj.show_name(obj))#打印更改后的属性 #删除属性 delattr(obj,'age')#删除一个变量中的属性或者方法 delattr(obj,'show_name') delattr(obj,'show_name111')#不存在,则报错 print(obj.__dict__)#打印obj的字典 # hasattr 判断某一个 变量 是否能够.调用一个名字,返回True或者False # getattr 直接获取一个变量中的名字的值 # setattr 为一个变量增加或者修改一个属性 # delattr 删除一个变量中的属性或者方法
d = {'k':'v'} #d.keys()
print(getattr(d,'keys')())
f = open() # f文件操作对象
f.read() # 文件对象.read方法
a.b 模块名.函数名 import my_moudle#引入一个模块 print(my_moudle.money)#打印my_money类的_money属性 print(getattr(my_moudle,'money'))#得到my_moudle的money属性 getattr(my_moudle,'qqxing')()#得到并运行qqxing函数
包
import 包名 ---> 包内的__init__文件
反射类中的名字
# getattr(类名,'静态属性')
# getattr(类名,'类方法')()
# getattr(类名,'静态方法')()
反射对象中的名字
# getattr(对象名,'对象属性')
# getattr(对象名,'方法名')()
反射模块中的名字
# import 模块名
# getattr(模块名,'模块中的变量')
# getattr(模块名,'模块中的函数')()
# getattr(模块名,'模块中的类名')
反射当前模块中的名字
# import sys
# getattr(sys.modules[__name__],'变量')
# getattr(sys.modules[__name__],'函数')()
# getattr(sys.modules[__name__],'类名')
import sys#引入sys模块 sys.modules[__name__] print(sys.modules[__name__])#<module '__main__' from '/Users/guoyuanjie/Desktop/day27/day27/3.反射.py'> # 所有导入过的模块 # {'字符串数据类型的模块名':模块的内存地址} # {'__main__':当前模块的内存地址}
类中的内置方法 __方法名__
魔术方法 双下方法
内置方法 : 是直接和python的语法隐形相关
len()内置函数 __len__()
hash()哈希函数 __hash__()
str() __str__()
l = [1,2,3,4]
len(l)
class A:#定义一个属性 def __init__(self,name,cls,age,sex):#初始化 self.name = name#name属性 self.cls = cls#cls属性 self.age = age#age属性 self.sex = sex#sex属性 def __eq__(self, other): if self.__dict__ == other.__dict__:return True return True def __len__(self):#__len__方法属性 return len(self.__dict__)#返回一个len(对象的字典的个数) hei = A('小黑','py10期',18,'无')#实例化小黑 hei2 = A('小2黑','py11期',17,'无')#实例化小黑二 def len(obj):#定义一个函数,传入对象 return obj.__len__()#返回一个对象属性 print(len(hei))#打印hei的个数4 print(hei.__dict__)#{'name': '小黑', 'cls': 'py10期', 'age': 18, 'sex': '无'}打印对象hei的字典方法 print(hei2.__dict__)#{'name': '小2黑', 'cls': 'py11期', 'age': 17, 'sex': '无'}打印对象hei2的字典方法 print(hei == hei2) # #True 两个对象就算值是完全相等的,但是仍然内存地址不同 # == 时间上是比较内存地址的 # == 实际上是调用了__eq__方法
format_dict={ 'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型 'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址 'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名 } class School: def __init__(self,name,addr,type):#初始化对象 self.name=name self.addr=addr self.type=type def __format__(self, format_spec):#定义一个__format__方法 return format_spec.format(obj=self)#返回一个 s1=School('oldboy1','北京','私立')#实例化一个北京的学校 print(format(s1,format_dict['tna']))#私立:oldboy1:北京 print(format(s1,format_dict['nat']))# oldboy1-北京-私立 print(format(s1,format_dict['tan']))# 私立/北京/oldboy1 print(format(s1,'tna'))# tna print(format(s1,'tan'))# tan
class School: def __init__(self,name,addr,type): self.name=name self.addr=addr self.type=type def __str__(self): return str(self.__dict__) def __repr__(self): # repr是str的备胎 return 'repr : school的repr对象' s1=School('oldboy1','北京','私立') print(str(s1))#{'name': 'oldboy1', 'addr': '北京', 'type': '私立'} print('%s'%s1)#{'name': 'oldboy1', 'addr': '北京', 'type': '私立'} print(s1)#{'name': 'oldboy1', 'addr': '北京', 'type': '私立'} print(repr(s1))#repr : school的repr对象 print('%r'%s1)#repr : school的repr对象 print('%s'%s1) # str __str__ # %s str 直接打印 内部都是调用了__str__
object __eq__,__str__,__repr__
del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo: def __del__(self): print('执行我啦') f1=Foo() del f1 print('------->') #输出结果 执行我啦 ------->
# 构造方法 创建一个对象的 # 初始化方法 __init__ 给已经创建出来的对象添加属性 # 析构方法 删除一个对象的时候调用的方法 import time class A: def __init__(self): self.f = open('userinfo','a') def consume(self): pass def __del__(self): '''在删除一个对象之前做一些收尾工作''' self.f.close() print('删除一个对象的时候调用我') a = A() time.sleep(1) del a # 删除一个对象的时候,如果内部存在__del__方法, # 那么在删除一个对象之前先执行__del__方法中的代码 print(a)
__new__构造方法
# new一个对象 # object.__new__() class A: def __init__(self):#初始化init方法 print('执行init方法了') def __new__(cls):#函数中先执行new方法 print('执行new方法了') return object.__new__(cls) # 创造对象,将对象返回 a = A()# print(type(a)) print(type(A)) # 先执行__new__方法 创造出一个对象 # 然后把创造出来的对象传递给__init__方法 # 会把self自动的返回,被a接收
元类
有一个元类 在创建类
type() 所有直接用class创建出来的类的元类都是type
class 类名(B,classMeta = 元类名)
class 类名(B,classMeta = type) # 默认
元类 创造 类 所以所有的类的type都是它的元类,默认是type
类 创造 对象 具体创造对象的方法 __new__方法,所有的对象的type都是它对应的类
python中 一切皆对象
变量 都有它属于的数据类型
设计模式
单例模式
一个类 可以被多次实例化 但是同一时间在python的内存中,只能有一个实例
class A: _instance = None#定义一个静态变量 def __init__(self,name):#初始化方法 '''给娃穿衣服''' self.name = name#定义一个动态属性 def __new__(cls, *args, **kwargs):#定义一个new方法 '''生娃的过程''' if not A._instance:#如果没有A._instance A._instance = object.__new__(cls)#类属性等于对象的属性 return A._instance#返回一个类属性 a1 = A('alex') # 第一次实例化的时候创造一个实例 print(a1.name)#alex a2 = A('egon') print(a1.name,a2.name,a1 is a2) # egon egon True
class A: def __init__(self,name): '''给娃穿衣服''' self.name = name def __new__(cls, *args, **kwargs): '''生娃的过程''' if not hasattr(A,'_instance'):#如果没有 A._instance = object.__new__(cls) return A._instance a1 = A('alex') # 第一次实例化的时候创造一个实例 print(a1.name)#alex a2 = A('egon') print(a1.name,a2.name) #egon egon
item系列
__getitem__\__setitem__\__delitem__
class A: def __init__(self,name):#初始化方法 self.name = name#定义一个静态属性 self.age = 81 def __getitem__(self, item):#查看一个对象的的方法 return self.__dict__[item] def __setitem__(self, key, value):#增加和修改一个动态属性 self.__dict__[key] = value def __delitem__(self, key):#删除一个动态属性 del self.__dict__[key] a = A('alex')#实例化 print(a['name']) #alex 对应了类中一个方法的语法#a.name==a['name'] print(a['age']) #81 对应了类中一个方法的语法#a.age==a['age'] # 增加 和 修改一个属性 a['sex'] = '不详'# a.sex = '不详'#增加一个a.sex='不祥' print(a.__dict__)#{'name': 'alex', 'age': 81, 'sex': '不详'} # print(a.sex) # print(a['sex']) a['sex'] = '女'#修改一个对象的动态属性 print(a.__dict__)#{'name': 'alex', 'age': 81, 'sex': '女'} del a['sex']#删除一个a['sex']的属性 print(a.__dict__)#{'name': 'alex', 'age': 81}
__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__ obj() # 执行 __call__
class A: def __call__(self,a): print('执行我了',a) def call(self,b): print('执行我了',b) a = A() a('aaa') # __call__ a.call('bbb')
hash
不可变的数据类型都可以被hash
class A: def __init__(self): self.a = 1 self.b = 2 def __hash__(self):#定义一个魔术方法 print(hash(str(12)))#同一时间字符串12的哈希值#7130726887503445041 return hash(str(self.a)+str(self.b))#同一时间返回一个哈希值'12'#7130726887503445041 a = A() print(hash(a))#返回对象的哈希值
class A:pass # def __hash__(self): # return 1 a = A() b = A() print(hash(a)) # object.__hash__()#同一时间同一个对象的hash值不管调用几次都相同 print(hash(a)) # object.__hash__() print(hash(a)) # object.__hash__() print(hash(a)) # object.__hash__() print(hash(a)) # object.__hash__() print(hash(a)) # object.__hash__() print(hash(a)) # object.__hash__() print(hash(b)) # object.__hash__() # dict的key set的元素 # dic key --> value # dic[key] = value # hash(obj)函数,obj对象对应的类必然内部实现了__hash__方法 # hash的结果就是__hash__方法的返回值 # 且在一次成的执行过程中是不会发生变化的 # 且要想作为字典的key或者作为集合的元素,这个对象对应的类必须实现__hash__方法
数据结构与算法 python 数据结构
python核心编程第二三版 基础
流畅的python 进阶
扑克牌例子
from collections import namedtuple#引用一个collections模块namedtuple可命名元祖 Card = namedtuple('Card',['rank','suit'])#创建一个可命名元祖 # card1 = Card(1,'红桃') class FranchDeck:#创建一个类 ranks = [str(n) for n in range(2,11)] + list('JQKA')#设定大小静态属性 suits = ['红心','方板','梅花','黑桃']#设置花色静态属性 def __init__(self):#初始化一个元祖属性 self._cards = [Card(rank,suit) for rank in FranchDeck.ranks for suit in FranchDeck.suits] def __len__(self):#定义一个len方法 return len(self._cards)# 返回对象的_cards属性的个数 def __getitem__(self, item):#查询方法 return self._cards[item]#返回一个对象属性的所有内容 def __setitem__(self, key, value): self._cards[key] = value deck = FranchDeck() print('**',deck[:]) from random import choice#引入选择模块 print(choice(deck)) # deck对象对应的类中的getitem方法和len方法 from random import shuffle#打乱顺序 shuffle(deck)#打印顺序 print('**',deck[:])
# 金融公司面试题 # 有一个类,对应这个类产生了100个对象 # 每个对象有三个属性 : 姓名 年龄 性别 # 请对这一百个对象进行去重,如果姓名和性别相同,即便年龄不同也是相同的对象 # 问最简便的方法? class Person:#定义一个类 def __init__(self,name,age,sex):#初始化属性 self.name = name#对象的name属性 self.age = age#对象的age属性 self.sex = sex#对象的sex属性 def __hash__(self):#定义哈希方法 return hash('%s%s'%(self.name,self.sex))#返回hash'self.name,self.sex'的值 def __eq__(self, other):#定义一个eq方法 if self.name == other.name and self.sex == other.sex:#如果对象属性等于 return True p_lst = []#定义个空列表 for i in range(100):#打印0到99 p_lst.append(Person('egon',i,'male'))#p_lst列表添加Person('egon',i,'male') p_lst.append(Person('alex',i,'male'))#p_lst列表添加Person('alex',i,'male') p_lst.append(Person('yuan',i,'male'))#p_lst列表添加Person('yuan',i,'male') print(p_lst) print(set(p_lst)) # 报错不可hash 完成了__hash__ # hash是否相等 __hash__ # 值是否相等 __eq__ # 收获1 # 对于一些python当中已经存在的内置函数 内置数据类型 内置模块中的方法 # 都有可能依赖于类中的内置方法 # 收获2 # set方法依赖集合中元素对象的__hash__ __eq__