面向对象进阶

 

一、isinstance和issubclass
isinstance(obj,cls)检查是否obj是否是类 cls 的对象

class Foo(object):
     pass
  
obj = Foo()
  
isinstance(obj, Foo)

  

issubclass(sub, super)检查sub类是否是 super 类的派生类

class Foo(object):
    pass
 
class Bar(Foo):
    pass
 
issubclass(Bar, Foo)

  


二、反射
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数

下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
hasattr(obj,xxx)方法:检测obj是否含有(xxx)属性 返回bool值
ret=getattr(obj,xxx)方法:获取xxx属性,没有则返回None(也可以设置默认值)

class Foo:
    f = '类的静态变量'
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say_hi(self):
        print('hi,%s'%self.name)

obj=Foo('egon',73)

#检测是否含有某属性
print(hasattr(obj,'name'))
print(hasattr(obj,'say_hi'))

#获取属性
n=getattr(obj,'name')
print(n)
func=getattr(obj,'say_hi')
func()
print(getattr(obj,'aaaaaaaa','不存在啊')) #报错

setattr(obj,key,value)方法:给对象增加新属性或者修改原有的属性
delattr(obj,xxx)方法:删除属性

class Foo:
    f = '类的静态变量'
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say_hi(self):
        print('hi,%s'%self.name)

obj=Foo('egon',73)



# #设置属性
setattr(obj,'sb',True)
setattr(obj,'show_name',lambda self:self.name+'sb')
setattr(obj,'name','haha')
print(obj.__dict__)
print(obj.show_name(obj))
print(obj.name)

# #删除属性
delattr(obj,'age')
delattr(obj,'show_name')
delattr(obj,'show_name111')#不存在,则报错
print(obj.__dict__)

3反射的应用

类也是对象

class Foo(object):
 
    staticField = "old boy"
 
    def __init__(self):
        self.name = 'wupeiqi'
 
    def func(self):
        return 'func'
 
    @staticmethod
    def bar():
        return 'bar'
 
print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')

反射当前模块成员

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import sys


def s1():
    print 's1'


def s2():
    print 's2'


this_module = sys.modules[__name__]

hasattr(this_module, 's1')
getattr(this_module, 's2')

导入其他模块,利用反射查找该模块是否存在某个方法

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def test():
    print('from the test')

复制代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
"""
程序目录:
    module_test.py
    index.py
 
当前文件:
    index.py
"""

import module_test as obj

#obj.test()

print(hasattr(obj,'test'))

getattr(obj,'test')()

  

 三、魔法方法

1、__str__和__repr__
改变对象的字符串显示__str__,__repr__
自定制格式化字符串__format__

#_*_coding:utf-8_*_

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 __repr__(self):
        return 'School(%s,%s)' %(self.name,self.addr)
    def __str__(self):
        return '(%s,%s)' %(self.name,self.addr)

    def __format__(self, format_spec):
        # if format_spec
        if not format_spec or format_spec not in format_dict:
            format_spec='nat'
        fmt=format_dict[format_spec]
        return fmt.format(obj=self)

s1=School('oldboy1','北京','私立')
print('from repr: ',repr(s1))
print('from str: ',str(s1))
print(s1)

'''
str函数或者print函数--->obj.__str__()
repr或者交互式解释器--->obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
注意:这俩方法的返回值必须是字符串,否则抛出异常
'''
print(format(s1,'nat'))
print(format(s1,'tna'))
print(format(s1,'tan'))
print(format(s1,'asfdasdffd'))
class B:

     def __str__(self):
         return 'str : class B'

     def __repr__(self):
         return 'repr : class B'


b=B()
print('%s'%b)
print('%r'%b)
%s和%r

 

2、 __new__、__init__、__del__

class Animal(object):

     def __new__(cls, *args, **kwargs):#覆盖了基类object的__new__方法  
         print("this is 构造方法")
         addr=super().__new__(cls) #必须调用父类开辟空间的方法(操作底层硬件) 默认传参 cls(当前类名)
         print("addr",addr)
         return addr
     def __init__(self,name,age):#覆盖了基类object的__init__方法
         print("self",self)
         print("this is 初始化方法")
         self.name=name
         self.age=age
     def __del__(self):  #覆盖了基类object的__del__方法
        print("i am 析构方法!")

alex=Animal("alex",34)
'''
alex=Animal("alex",34)
类实例化过程:
   1 __new__方法获得空间地址(实例对象创建第一步必须创建空间)
   2 将空间地址作为第一个位置参数传给__init__ ,完成实例空间赋值属性的过程   self变量等于addr变量  存储地址空间指针
   3 空间地址失去了实例对象的指向(或者程序结束) 会调用__del__
'''
class Config(object):
    _instance=None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance=super().__new__(cls)
        return cls._instance
    file_path=""
    data="mysql"
    app=["app01","app02"]

cf=Config()
cf2=Config()

print(id(cf))
print(id(cf2))
print(cf == cf2)
单例模型
# python 垃圾回收机制: 任何对象在执行过程中失去了指引,则被回收
class Animal(object):
    def __del__(self):
        print("i am 析构方法!")

a=Animal()
del a
import time
time.sleep(10)


class FileHanlde(object):
    path="......."
    def __init__(self):
        self.f=open(self.path,"r")
    def read(self):
        return self.f.read()
    def __del__(self):
        self.f.close()

fh=FileHanlde()
fh.read()
析构回收机制

 

3、item系列:__getitem__\__setitem__\__delitem__

class Animal(object):
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def __getitem__(self,item):
        print('item',item)
        return getattr(self,item,None)  #getattr判断item属不属于self 属于就返回  不属于就返回None

    def __setitem__(self, key, value):#可以应用于数据库插入一条数据(写一个功能)
        print(key)
        print(value)

    def __delitem__(self, key):
        print("del item",key)

alex=Animal("alex",45)
# print(alex.name)
# alex.name="xxxx"
# print(alex.name)
print(alex["name"]) # alex.name  alex['xxx'] print 得到数据会调用 __getitem__
print(alex["age"]) # alex.age
print(alex['gender'])
print(alex.__dict__)
alex["gender"]="male"  #会调用__setitem__  可以应用于数据库插入一条数据
alex['age'] = 55
print(alex.__dict__)
del alex["xxx"]  #会调用__delitem__


# info={"name":"alex","age":"123"}
# info["gneder"]="male"
例子1
class Foo:
    def __init__(self,name,addr):
        self.name=name
        self.addr=addr

    def __getitem__(self, item):
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        self.__dict__[key]=value
    def __delitem__(self, key):
        print('del obj[key]时,我执行')
        self.__dict__.pop(key)
    def __delattr__(self, item):
        print('del obj.key时,我执行')
        self.__dict__.pop(item)

f1=Foo('sb','haxi')
f1['age']=18
f1['age1']=19
print(f1.__dict__)
del f1.age1
del f1['age']
del f1['addr']
print(f1.__dict__)
f1['name']='alex'
print(f1.__dict__)
例子2

 

4、__getattr__、__setattr__

class Animal(object):
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def __getattr__(self, item):
        print("getattr",item)
        return "对象没有%s属性!"%item

    def __setattr__(self, key, value):
        print("空间地址%s为%s属性赋值%s"%(self,key,value))
        super().__setattr__(key, value)

alex=Animal("alex",56) #实例化过程中__init__回去调用__setattr__
print(alex.gender)
alex.name="李杰"
print(alex.name)
例子

 

5、__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Animal(object):
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def run(self):
        pass

    def __call__(self, *args, **kwargs):
        print(" i am call 方法!")

alex=Animal("alex",12)
print(callable(Animal))
print(callable(Animal.run))
print(callable(alex.run))
print(callable(alex)) # False
alex()
View Code

 

__len__

复制代码
class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __len__(self):
        return len(self.__dict__)
a = A()
print(len(a))
复制代码

 

__hash__

复制代码
class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __hash__(self):
        return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))
复制代码

 

__eq__

复制代码
class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __eq__(self,obj):
        if  self.a == obj.a and self.b == obj.b:
            return True
a = A()
b = A()
print(a == b)
复制代码

 

复制代码
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):
        return len(self._cards)

    def __getitem__(self, item):
        return self._cards[item]

deck = FranchDeck()
print(deck[0])
from random import choice
print(choice(deck))
print(choice(deck))
复制代码
复制代码
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):
        return len(self._cards)

    def __getitem__(self, item):
        return self._cards[item]

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

deck = FranchDeck()
print(deck[0])
from random import choice
print(choice(deck))
print(choice(deck))

from random import shuffle
shuffle(deck)
print(deck[:5])
复制代码
复制代码
class Person:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

    def __hash__(self):
        return hash(self.name+self.sex)

    def __eq__(self, other):
        if self.name == other.name and self.sex == other.sex:return True


p_lst = []
for i in range(84):
    p_lst.append(Person('egon',i,'male'))

print(p_lst)
print(set(p_lst))
复制代码

 

posted @ 2019-03-01 18:12  冥想心灵  阅读(168)  评论(0编辑  收藏  举报