面向对象详细

一 isinstance(obj,cls)和issubclass(sub,super)class Foo:def __init__(self,name):se

一 isinstance(obj,cls)和issubclass(sub,super)

class Foo:
    def __init__(self,name):
        self.name = name

obj = Foo("egon")

print(isinstance(obj,Foo))


l = list([1,2,3])
print(isinstance(l,list))

-----------------结果-----------

True
True
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
class Foo:
    pass

class Bar(Foo):
    pass

print(issubclass(Bar,Foo))

------------------------结果----------
True
issubclass(sub, super)检查sub类是否是 super 类的派生类

二.反射

  1.python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

class People:
    country = "china"
    def __init__(self,name):
        self.name = name


p = People("egon")
print(p.__dict__)
#-------------------------
print(hasattr(p,"name"))
print("name" in p.__dict__)
print(hasattr(People,"country"))

----------------------------------
{'name': 'egon'}
True
True
True
hasattr(object,name)
class People:
    country = "china"
    def __init__(self,name):
        self.name = name

    def walk(self):
        print("%s is working" % self.name)

p = People("egon")

print(getattr(p,"country"))     #print(p.country)
    # china
print(getattr(p,"walk"))        #print(p.walk)
    #<bound method People.walk of <__main__.People object at 0x101979278>>
getattr(object, name, default=None)
class People:
    country = "china"
    def __init__(self,name):
        self.name = name

    def walk(self):
        print("%s is working" % self.name)

p = People("egon")

setattr(p,"age",15)
print(p.__dict__)
    {'age': 15, 'name': 'egon'}
setattr(x, y, v)
class People:
    country = "china"
    def __init__(self,name):
        self.name = name

    def walk(self):
        print("%s is working" % self.name)

p = People("egon")

print(p.__dict__)
    {'name': 'egon'}
delattr(p,"name")
print(p.__dict__)
    {}
delattr(x, y)
import sys
def add():
    print("add")

def delete():
    print("delete")

def update():
    print("update")

def search():
    print("search")

this_module = sys.modules[__name__]
while True:
    cmd = input("please input: ")
    if not cmd:continue
    if hasattr(this_module,cmd):
        func = getattr(this_module,cmd)
        func()
sys.modules[__name__]

  2.反射的好处 

  好处一:实现可插拔机制

  有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,

      lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。

  总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?

      即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能 

#Ftpclent.py 文件

class FtpClient:
    'ftp客户端,但是还么有实现具体的功能'
    def __init__(self,addr):
        print('正在连接服务器 %s ' %addr)
        self.addr=addr

    def get(self):
        print("get")


#Ftpserver.py  文件

from day32 import FtpClient

obj =  FtpClient.FtpClient('192.168.1.1')

if hasattr(obj,"get"):
    func = getattr(obj,"get")
    func()

print("other func")
FTP 代码

   好处二:动态导入模块(基于反射当前模块成员)

1
2
3
4
5
6
7
8
#导入字符串
__import__("time")
 
#使用模块
import importlib
t = importlib.import_module("time")
print(t.time())
    1493026292.217129

三.__setattr__,__delattr__,__getattr__

#初始化和赋值时触发__setattr__运行


#发现__dict__没有name 和 age
class Foo:
    def __init__(self,name):
        self.name = name

    def __setattr__(self, key, value):
        print("__setattr__  key:%s value:%s"%(key,value))

obj = Foo("egon")
     __setattr__  key:name value:egon
obj.age = 18
     __setattr__  key:age value:18
print(obj.__dict__)           #发现__dict__没有name 和 age
     {}


#初始化和赋值都在__dict__中找到

class Foo:
    def __init__(self,name):
        self.name = name

    def __setattr__(self, key, value):
        print("__setattr__  key:%s value:%s"%(key,value))
        self.__dict__[key] = value

obj = Foo("egon")
    __setattr__  key:name value:egon
obj.age = 15
    __setattr__  key:age value:15
print(obj.__dict__)
    {'name': 'egon', 'age': 15}



#初始化赋值时判断如果不是数字不可以赋值

class Foo:
    def __init__(self,name):
        self.name = name

    def __setattr__(self, key, value):
        if not isinstance(value,int):
            raise TypeError("type error")
        self.__dict__[key] = value

obj = Foo(15)
obj.age = 15
print(obj.__dict__)
    {'age': 15, 'name': 15}
__setattr__
class Foo:
    def __init__(self,name):
        self.name = name

    def __setattr__(self, key, value):
        self.__dict__[key] = value

    def __delattr__(self, item):
        self.__dict__.pop(item)
obj = Foo("egon")

print(obj.__dict__)
    {'name': 'egon'}
del obj.name
print(obj.__dict__)
    {}
__delattr__ 
#属性不存在时候运行

class Foo:
    def __init__(self,name):
        self.name = name

    def __getattr__(self, item):
        print("__getattr__  %s" % item)

obj = Foo("egon")
print(obj.name)
    egon
print(obj.xxx)
    __getattr__  xxx
    None 
__getattr__

四. 二次加工标准类型(包装)

包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工) 

#自定义自己的数据类型,追加和插入,如果不是数字,报错

class List(list):
    def append(self, p_object):
        if not isinstance(p_object,int):
            raise TypeError("Type error")
        super().append(p_object)

    def insert(self, index, p_object):
        if not  isinstance(p_object,int):
            raise TypeError("Type error")
        super().insert(index,p_object)

l = List([1,2,3])
print(l)
    [1, 2, 3]
l.append("4")   #不能追加字符串

l.insert(0,-1)
print(l)
    [-1, 1, 2, 3]
自定义数据类型
import time

class Open:
    def __init__(self,filepath,mode="r",encode="utf-8"):
        self.x = open(filepath,mode=mode,encoding=encode)
        self.filepath = filepath
        self.mode = mode
        self.encoding = encode

    def write(self,value):
        log_time = time.strftime('%Y-%m-%d %X')
        self.x.write("%s %s" % (log_time,value))

    def __getattr__(self, item):
        return getattr(self.x,item)

f = Open("b.txt","a+")
f.write("11111111\n")
f.seek(0)
print(f.read())
授权
#基于继承来定制自己的数据类型
class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid
    def append(self, p_object):
        ' 派生自己的append:加上类型检查'
        if not isinstance(p_object,int):
            raise TypeError('must be int')
        super().append(p_object)

    @property
    def mid(self):
        '新增自己的属性'
        index=len(self)//2
        return self[index]


l=List([1,2,3])
print(l.mid)



基于授权来定制自己的数据类型:

class Open:
    def __init__(self,filepath,mode,encode='utf-8'):
        self.f=open(filepath,mode=mode,encoding=encode)
        self.filepath=filepath
        self.mode=mode
        self.encoding=encode

    def write(self,line):
        print('write')
        self.f.write(line)

    def __getattr__(self, item):
        return getattr(self.f,item)


f=Open('a.txt','w')
f.write('123123123123123\n')
print(f.seek)
f.close()
授权 继承 数据类型

五.反射作业

1
2
3
4
1.基于授权定制自己的列表类型,要求定制的自己的__init__方法,
2.定制自己的append:只能向列表加入字符串类型的值
3.定制显示列表中间那个值的属性(提示:property
4.其余方法都使用list默认的(提示:__getattr__加反射)
class List:
    def __init__(self,x):
        self.seq=list(x)

    def append(self,value):
        if not isinstance(value,str):
            raise TypeError('must be str')
        self.seq.append(value)
    @property
    def mid(self):
        index=len(self.seq)//2
        return self.seq[index]
    def __getattr__(self, item):
        return getattr(self.seq,item)

    def __str__(self):
        print("111")
        return str(self.seq)

l=List([1,2,3])

l.append('1')

print(l.mid)

l.insert(0,123)
View Code

六.__setitem__,__getitem,__delitem__

#把对象操作属性模拟成字典的格式

class Foo:
    def __init__(self,name):
        self.name = name

    def __getitem__(self, item):
        return self.__dict__[item]
    def __setitem__(self, key, value):
        self.__dict__[key] = value
    def __delitem__(self, item):
        self.__dict__.pop(item)


f = Foo("egon")
print(f.name)
    egon
f.name = "egonlin"
print(f.__dict__)
    {'name': 'egonlin'}

f["age"] = 18
print(f.__dict__)
    {'name': 'egon', 'age': 18}

del f["name"]
print(f.__dict__)
    {}
把对象操作属性模拟成字典的格式

七.__slots__

八.__next__和__iter__实现迭代器协议

class Foo:
    def __init__(self, end,start=0):
        self.start = start
        self.end = end
    def __iter__(self):
        return self

    def __next__(self):
        if self.start >= self.end:
            raise StopIteration
        n = self.start
        self.start+=1
        return n

f = Foo(10)
for i in f:
    print(i)
rangge(10)
class Range:
    def __init__(self,start,stop):
        self.start = start
        self.stop = stop

    def __iter__(self):
        return self

    def __next__(self):
        if  self.start >= self.stop:
            raise StopIteration("StopIteration Error")
        n = self.start
        self.start += 1
        return n

obj = Range(0,15)

for i in obj:
    print(i)
Range(1,15)
class Range:
    def __init__(self, *args):
        self.args = args
        if len(self.args) == 2:
            self.start = self.args[0]
            self.end = self.args[1]
        else:
            self.start = 0
            self.end = self.args[0]
    def __iter__(self):
        return self

    def __next__(self):
        n = self.start
        if n < self.end:
            n = self.start
            self.start += 1
            return n
        raise StopIteration


for i in Range(1,10):
    print(i)

for i in Range(10):
    print(i)
range(10) range(1,15)
class Fib:
    def __init__(self):
        self._a=0
        self._b=1

    def __iter__(self):
        return self

    def __next__(self):
        self._a,self._b=self._b,self._a + self._b
        return self._a

f1=Fib()

print(f1.__next__())
print(next(f1))
print(next(f1))

for i in f1:
    if i > 100:
        break
    print('%s ' %i,end='')
斐波那契数列

九.__del__

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

class Foo:

    def __del__(self):
        print('执行我啦')

f1=Foo()
del f1
print('------->')
--------------------结果-------------

执行我啦
------->
销毁--->执行完
class Foo:

    def __del__(self):
        print('执行我啦')

f1=Foo()
print('------->')
--------------------结果-------------

------->
执行我啦
执行完--->销毁

十.__enter__和__exit__

with open('a.txt') as f:
   '代码块'
 
上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
 
class Open:
    def __init__(self,name):
        self.name=name
 
    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
        # return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行我啊')
 
 
with Open('a.txt') as f:
    print('=====>执行代码块')
     
-----------------结果----------------
 
出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
=====>执行代码块
with中代码块执行完毕时执行我啊
说明
class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行我啊')
        print(exc_type)
        print(exc_val)
        print(exc_tb)



with Open('a.txt') as f:
    print('=====>执行代码块')
    raise AttributeError('***着火啦,救火啊***')
print('0'*100) #------------------------------->不会执行
__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行
class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行我啊')
        print(exc_type)
        print(exc_val)
        print(exc_tb)
        return True



with Open('a.txt') as f:
    print('=====>执行代码块')
    raise AttributeError('***着火啦,救火啊***')
print('0'*100) #------------------------------->会执行
如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行
import time

class Open:
    def __init__(self,filepath,mode="r",encode="utf-8"):
        self.x = open(filepath,mode=mode,encoding=encode)
        self.filepath = filepath
        self.mode = mode
        self.encoding = encode

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.x.close()
        return True

    def write(self,value):
        log_time = time.strftime('%Y-%m-%d %X')
        self.x.write("%s %s" % (log_time,value))

    def __getattr__(self, item):
        return getattr(self.x,item)


with Open("b.txt","a+") as f :    #obj = Open().__enter__() ---> obj = f
    f.write("11111111\n")
Open类 with打开

十一.__call__

对象后面加括号,触发执行。

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

1
2
3
4
5
6
7
8
9
10
11
class Foo:
    def __init__(self):
        pass
 
    def __call__(self, *args, **kwargs):
        print('__call__')
 
 
obj = Foo()  # 执行 __init__
obj()  # 执行 __call__
    __call__

十二.__str__

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

    def __str__(self):
        return "名字是%s 年龄是%s" %(self.name,self.age)

f1 = Foo("agon",18)
print(f1)

# --------------结果----------
名字是agon 年龄是18
__str__ 打印时候触发

十三.__new__

 __new__ 单例

十四. 创建类

复制代码
1. 类在创建的时候执行type的__init__方法  类相当于type的对象
2. 类() = type对象() 相当于实例化 执行type的__call__方法
3. type的__call__方法会调用
    - 调用类的__new__方法 用于创建对象
    - 调用类的__init__方法 用于初始化
4. 对象() 执行类的__call__方法
复制代码
-------------------------------(一)-------------------------------

class SingletonType(type):

    def __init__(self,*args,**kwargs):
        super(SingletonType,self).__init__(*args,**kwargs)



class Foo(metaclass=SingletonType):
    pass


类默认是由type创建也可以指定metaclass创建 在父类构造方法继续让type执行 相当于没做什么操作
对象是由类创建的

-------------------------------(二)-------------------------------

class SingletonType(type):

    def __init__(self,*args,**kwargs):
        print(self)
        super(SingletonType,self).__init__(*args,**kwargs)



class Foo(metaclass=SingletonType):
    pass


此时在父类里面打印print(self) 发现结果为<class '__main__.Foo'>

对象是类创建 创建对象时候类的__init__方法自动执行
类是type创建 创建类时候type的__init__方法自动执行


-------------------------------(三)-------------------------------


对象() 执行类的__call__方法
类() 执行type的__call__方法 执行__call__方法内部会调用(类的__new__方法和__init__方法)


class SingletonType(type):

    def __init__(self,*args,**kwargs):
        print(self)
        super(SingletonType,self).__init__(*args,**kwargs)

    def __call__(cls, *args, **kwargs): # cls 表示 SingletonType类
        obj = cls.__new__(cls, *args, **kwargs)                # obj 为创建的对象


class Foo(metaclass=SingletonType):

    def __new__(cls, *args, **kwargs):
        return object.__new__(cls, *args, **kwargs)


-------------------------------(四)-------------------------------



class SingletonType(type):

    def __init__(self,*args,**kwargs):
        print(self)
        super(SingletonType,self).__init__(*args,**kwargs)

    def __call__(cls, *args, **kwargs):    # cls 表示 SingletonType类
        obj = cls.__new__(cls, *args, **kwargs)

        cls.__init__(obj,*args, **kwargs)  # 实例化 底下两者效果相同
        #obj.__init__(*args, **kwargs)
        return obj

class Foo(metaclass=SingletonType):

    def __init__(self):
        pass

    def __new__(cls, *args, **kwargs):
        return object.__new__(cls, *args, **kwargs)


obj = Foo()
创建类 对象 流程

 

元类是用来如何创建类的 正如类是创建对象的模版一样

元类的实例是类  正如类的实例为对象

一个类如果没有声明自己的元类,默认他的元类就是type, 也可以通过继承type来自定义元类


def __init__(self,name,age):
    pass

obj = type('foo',(object,),{'x':1,'__init__':__init__})
    #参数一: 类名
    #参数二: 继承类
    #参数三: 类的属性 方法


type 实例化结果就是一个类
View Code