hechengwei

导航

Python开发——10.面向对象编程进阶

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

1.isinstance(obj,cls)

  判断obj是不是由cls产生的类

2.issubclass(sub,super)

  判断sub是否是super的子类

3.代码

class Foo:
    def __init__(self,name):
        self.name = name
class Son(Foo):
    # pass
    def __init__(self,name):
        self.name = name
f1 =Foo("dazui")
f2 = Son("zuizui")
print(isinstance(f1,Foo))#True,判断对象是否由类实例化而来的
print(isinstance(f2,Foo))#True
print(isinstance(f2,Son))#True

print(issubclass(Son,Foo))#True
print(issubclass(Foo,Son))#False
print(type(f1),type(f2))#<class '__main__.Foo'> <class '__main__.Son'>

 

二、反射

1.定义

  通过字符串的形式操作对象相关的属性。

2.四个函数

class Intermedia:
    def __init__(self,name,addr):
        self.name = name
        self.addr = addr
    def rent_house(self):
        print("%s正在租房子"%(self.name))
i1 = Intermedia("自如","翠屏山")
#hasattr:判断对象是否包含指定的数据属性,也可以判断类是否包含指定的函数属性
print(hasattr(i1,"name"))#True
print(hasattr(Intermedia,"rent_house"))#True
#getattr:传入三个参数,如果数据属性存在,则返回该数据属性的值,不存在则返回指定的内容
print(getattr(i1,"name","自定义的内容"))#i1没有nam22e这个属性,打印“自定义内容”
#setattr:设置数据属性和函数属性
setattr(i1,"price",1600)
print(i1.__dict__)#{'price': 1600, 'name': '自如', 'addr': '翠屏山'}
#删除属性
delattr(i1,"price")
print(i1.__dict__)#{'name': '自如', 'addr': '翠屏山'}
delattr(Intermedia,"rent_house")

 

3.优点

(1)实现可插拔机制

class FtpClient:
    "Ftp客户端,但具体功能还没实现"
    def __init__(self,addr):
        self.addr = addr
    def put(self):
        print("正在上传文件")
from ftp_client import FtpClient

f1 = FtpClient("1.1.1.1")
if hasattr(f1,"put"):
    func_get = getattr(f1,"put")
    func_get()
else:
    print("执行其他功能")

 

(2)动态导入模块

import  importlib
module_t = importlib.import_module("m1.test")
print(module_t)#<module 'm1.test' from 'D:\\python_s3\\day27\\m1\\test.py'>
module_t.test1()
module_t._test2()
from m1 import test
test.test1()
test._test2()

module_t = __import__("m1.test")
print(module_t)#<module 'm1' from 'D:\\python_s3\\day27\\m1\\__init__.py'>
module_t.test.test1()
module_t.test._test2()

from m1.test import *
test1()
_test2()#用*的方式导入找不到_test2()
from m1.test import test1,_test2
test1()
_test2()

 

三、__setattr__、__delattr__和__getattr__

class Foo:
    y = 24
    def __init__(self,x):
        self.x = x
    def __getattr__(self, item):
        print("执行__getattr__")
    def __delattr__(self, item):
        print("执行__delattr__")
    def __setattr__(self, key, value):
        print("执行__setattr__")
        self.__dict__[key] = value
f1 = Foo(8)

#__getattr__,当要找的属性不存在时,执行__getattr__
getattr(f1,"不存在")#执行__getattr__
#__delattr__:当实例删除属性时,执行
del f1.y#执行__delattr__
del Foo.y#不执行__delattr__
#设置属性时执行__setattr__
f1 = Foo(8)#执行__setattr__
f1.z = 6#执行__setattr__

 

四、二次加工标准类型

1.包装

  利用继承和派生知识,基于标准的数据类型来定制需求的数据类型,新增或改写方法。包装一个类型通常是对已存在的类型的一些定制,可以新建、修改或删除原有功能,其他保持不变

class List(list):
    def append(self, p_object):
        if type(p_object)==str:
            # list.append(self,p_object)
            super().append(p_object)
        else:
            print("输入的不是字符串类型")
    def show_middle(self):
        return self[int(len(self)/2)]
l = List("hello world!")
print(l)
l.append(123)#输入的不是字符串类型

 

2.授权

  授权是包装的一个特性,授权的过程是所以更新的功能都由新类的某部分来处理,已存在的功能设为对象的默认属性

import time
class Open:
    def __init__(self,filename,mode,encoding="utf-8"):
        # self.filename = filename
        self.file = open(filename,mode,encoding=encoding)
        self.mode = mode
        self.encoding = encoding
    def write(self,line):
        t = time.strftime("%Y-%m-%D %X")
        self.file.write("%s %s" %(t,line))
    def __getattr__(self, item):
        return getattr(self.file,item)
f1 = Open("a.txt","w")
f1.write("111111\n")
f1.write("222222\n")

 

五、__getattribute__  

class Foo:
    def __init__(self,name):
        self.name = name
    def __getattr__(self, item):
        print("执行getattr")
    def __getattribute__(self, item):#无论能否找到都执行__getattribute__,只有抛出AttributeError时会执行__getattr__        print("执行getattribute")
        raise AttributeError("抛出异常")#会去执行__getattr__
        # raise TabError("抛出异常")#不会去执行__getattr__

f1 = Foo("大嘴")
f1.age

 

六、__setitem__、__getitem__和__delitem__

class Foo:
    def __init__(self,name):
        self.name = name
    def __getitem__(self, item):
        print("执行__getitem__")
        return self.__dict__[item]
    def __setitem__(self, key, value):
        print("执行__setitem__")
    def __delitem__(self, key):
        print("执行__delitem__")

f1 = Foo("dazui")

print(f1["name"])#执行__getitem__
f1["age"]=18#执行__setitem__
del f1["name"]#执行__delitem__

 

七、__str__、__repr__和__format__

1.利用__str__或__repr__改变对象的字符串显示

class Foo:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __str__(self):
        return "这是str的返回结果  name:%s age: %s" %(self.name,self.age)
    def __repr__(self):
        return "这是repr的返回结果  name:%s age: %s" %(self.name,self.age)
f1 = Foo("大嘴",80)
print(f1)#<__main__.Foo object at 0x001D5F30>默认显示,\
# 定义__str__时,显示str的返回值;没有__str__,定义了__repr__,显示repr的返回值

 

2.利用__format__定制格式化字符串

format_dic={
    "ymd":"{0.y} {0.m} {0.d}",
    "y:m:d":"{0.y}:{0.m}:{0.d}",
    "d-m-y":"{0.d}-{0.m}-{0.y}"
}
class Data:
    def __init__(self,y,m,d):
        self.y = y
        self.m = m
        self.d = d
    def __format__(self, format_spec):
        print("执行__format__")
        print(format_spec)
        if not format_spec or format_spec not in format_dic:
            format_spec = "ymd"
        fm = format_dic[format_spec]
        return fm.format(self)

d1 = Data(2018,5,18)
print(format(d1,"yaaaaaaaaa"))

 

八、__slots__

# 节省内存,对象不能新建数据属性
class Foo:
    __slots__ = ["name","age"]
f1=Foo()
print(Foo.__slots__)
print(f1.__slots__)
f1.name = "dazui"
f1.age = 80
print(f1.name,f1.age)
f1.gender = "female"#'Foo' object has no attribute 'gender'

 

九、__next__和__iter__实现迭代器协议

1.代码

class Foo:
    def __init__(self,x):
        self.x = x
    def __iter__(self):
        return self
    def __next__(self):
        if self.x == 15:
            raise StopIteration("迭代器中止")
        self.x += 1
        return self.x
f1 = Foo(10)
print(f1.__next__())
print(next(f1))
for i in f1:#从13开始循环
    print(i)

 

2.实现菲波那切数列

class Fib:
    def __init__(self,a,b):
        self._a = a
        self._b = b
    def __iter__(self):
        return self
    def __next__(self):
        if self._a>200:
            raise StopIteration
        self._a,self._b = self._b,self._a+self._b
        return self._a
f1 = Fib(1,2)
print(next(f1))
print(f1.__next__)
print("<><><><><><><><><><><><><><><><>")
for i in f1:
    print(i)

 

十、__doc__

#描述信息不会被继承
class Foo:
    "Foo的描述信息"
    pass
class Son(Foo):
    pass
print(Foo.__doc__)#Foo的描述信息
print(Son.__doc__)#None

 

十一、__module__和__class__

__module__表示当前操作对象在哪个模块

__class__表示当前操作对象的类

from test.test1 import Foo
f1 = Foo("dazui")
print(f1.__module__)#test.test1
print(f1.__class__)#<class 'test.test1.Foo'>

 

十二、__del__

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

class Foo:
    def __init__(self,name):
        self.name = name
    def __del__(self):
        print("执行析构函数")
f1 = Foo("dazui")#执行析构函数
# del f1.name
# print("<><>")#先打印"<><>",然后执行构析函数释放内存
#<><>
# 执行析构函数
del f1#先执行构析函数释放内存,然后打印"<><>"
print("<><>")
#执行析构函数
# <><>

 

十三、__call__

#对象后面加(),触发执行
class Foo:
    def __call__(self, *args, **kwargs):
        print("执行__call__")
f1 = Foo()
f1()#执行__call__

 

十四、__enter和__exit__

1.with语句

  又称上下文管理协议,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法

2.优点

(1)使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预

(2)在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制。

3.代码

class Foo:
    def __init__(self,name):
        self.name = name
    def __enter__(self):
        print("执行__enter__")#出现with语句,执行,返回值赋给as声明的变量
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("执行__exit__")
        print(exc_type)#异常类
        print(exc_val)#异常值
        print(exc_tb)#追踪信息
        return True#异常被清空,with后面的语句正常执行,如不返回,会抛出异常,,程序停止执行
with Foo("a.txt") as f :
    print(f)
    print(大嘴)
print("<><><><><><><><><><><>")

 

十五、metaclass

  元类是类的类,元类创建类正如类创建对象,当一个类没有声明自己的元类,它的默认元类就是type,,除了使用元类type,用户也可通过继承type来自定义元类

1.另一种定义类的方式

def __init__(self,name,age):
    self.name = name
    self.age = age
def test(self):
    print("test")
Foo = type("Foo",(object,),{"x":1,"__init__":__init__,"test":test})
f1 = Foo("dazui",18)
print(f1.name)
f1.test()

2.自定义元类

 

class MyType(type):
    def __init__(self,a,b,c):
        print(self,a,b,c)
        print("元类的构造函数执行")
    def __call__(self, *args, **kwargs):
        print(self,*args,**kwargs)
        obj = object.__new__(self)
        self.__init__(obj,*args,**kwargs)
        return obj
class Foo(metaclass=MyType):
    def __init__(self,name):
        self.name = name
f1 = Foo("alex")

 

 

 

十六、property

  一个静态属性property本质就是实现了get、set、delete三种方法

class Goods:
    def __init__(self):
        self.original_price = 100
        self.discount = 0.8

    @property
    def new_price(self):
        new_price = self.original_price*self.discount
        return new_price
    @new_price.setter
    def price(self,value):
        self.original_price = value
    @new_price.deleter
    def del_price(self):
        del self.original_price
g1 = Goods()
print(g1.new_price)
g1.price = 200
print(g1.original_price)

del g1.original_price
class Foo:
    def get_AAA(self):
        print("get的时候运行")
    def set_AAA(self,value):
        print("get的时候运行")
    def del_AAA(self):
        print("del的时候运行")
    AAA = property(get_AAA,set_AAA,del_AAA)
f1 = Foo()
f1.AAA = "aaa"
del f1.AAA

 

十七、 描述符

1.描述符定义

  描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__()和__delete__()中的一个

   __get__():调用一个属性时触发

  __set__():设置一个属性时触发

   __get__():调用一个属性时触发

2.作用

  描述符是用来代理另外一个类的属性,必须把描述符定义为这个类的类属性,不能定义到构造函数中

3.分类

(1)数据描述符:至少实现了__get__()和__set__()

(2)非数据描述符:没有实现__set__()

4.优先级

  从高到低类属性>s数据描述符>实例属性>非数据描述符>找不到属性触发__getattr__()

5.描述符的应用

class Nametype:
    def __init__(self,key,expected_type):
        self.key = key
        self.expected_type = expected_type
    def __get__(self, instance, owner):
        print("__get__方法")
        return instance.__dict__[self.key]
    def __set__(self, instance, value):
        print("__set__方法")
        if not isinstance(value,self.expected_type):
            raise TypeError("%s输入类型错误,不是%s" %(self.key,self.expected_type))
        instance.__dict__[self.key] =value
    def __delete__(self, instance):
        instance.__dict__.pop(self.key)

class People:
    name = Nametype("name",str)
    age = Nametype("age",int)
    def __init__(self,name,age,salary):
        self.name = name
        self.age = age
        self.salary = salary
p1 = People("dazui","18",19999)

 

6.类的装饰器

def deco(obj):
    print(obj)
    obj.x = 1
    obj.y = 2
    obj.z = 3
    return obj
@deco#Foo = deco(Foo)
class Foo:
    pass
print(Foo.__dict__)
def Typed(**kwargs):
    def deco(obj):
        for key,val in kwargs.items():
            setattr(obj,key,val)
            return obj
    return deco
@Typed(x = 1,y = 2,z= 3)
class Foo:
    pass

print(Foo.__dict__)

@Typed(name = "dazui")
class Bar:
    pass
print(Bar.__dict__)

 

7.类的装饰器应用

class Nametype:
    def __init__(self,key,expected_type):
        self.key = key
        self.expected_type = expected_type
    def __get__(self, instance, owner):
        return instance.__dict__[self.key]
    def __set__(self, instance, value):
        if not isinstance(value,self.expected_type):
            raise TypeError("%s输入类型错误,不是%s" %(self.key,self.expected_type))
        instance.__dict__[self.key] =value
    def __delete__(self, instance):
        instance.__dict__.pop(self.key)

def deco(**kwargs):
    def wrapper(obj):
        for key,val in kwargs.items():
            setattr(obj,key,Nametype(key,val))
        return obj
    return wrapper



@deco(name = str,age = int)
class People:
    def __init__(self,name,age,salary):
        self.name = name
        self.age = age
        self.salary = salary
p1 = People("dazui","18",1000)
print(p1.__dict__)
类的装饰器应用

 

posted on 2018-05-21 21:45  hechengwei  阅读(204)  评论(0编辑  收藏  举报