面向对象进阶、反射

  isinstance和issubclass

  • 反射
    •   setattr
    •   delattr
    •   getattr
    •   hasattr
  • __str__和__repr__
  • __del__
  • item系列
    •   __getitem__
    •   __setitem__
    •   __delitem__
  • __new__
  • __call__
  • __len__
  • __hash__
  • __eq__

 

isinstance和issubclass

 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__

 

posted @ 2018-03-12 15:01  虫洞小鳗鱼  阅读(210)  评论(0编辑  收藏  举报