Python面向对象进阶

上篇回顾python

  • 面向对象是一种编程方式,此编程方式的实现是基于对  和 对象 的使用
  • 类 是一个模板,模板中包装了多个“函数”供使用(能够讲多函数中公用的变量封装到对象中)
  • 对象,根据模板建立的实例(即:对象),实例用于调用被包装在类中的函数
  • 面向对象三大特性:封装、继承和多态
  • 静态属性(@property) 特色:将函数属性假装成数据属性(封装逻辑)
  • 静态方法(@staticmethod) 跟类和实例无关系,名义上归属类管理,但不能使用类变量和实例变量
  • 类方法(@classmethod) 跟实例没有关系,类本身调用;只能访问类的属性,不能访问实例属性,不须要self参数,自动加cls参数
  • 面向对象的专业术语

本篇介绍程序员

  反射编程

  • 根据字符串的形式去某个对象中操做它的成员
  • 四个能够实现反射的函数(也适用于对象和类)
class Sea: #
    def __init__(self,name,country,addr):
        self.name = name
        self.country = country
        self.addr = addr
    def sea_wave(self):
        print("一波儿海啸正在来袭")
s1 = Sea("东海","哥雅王国","风车村")

print(hasattr(s1,"name")) # 判断有没有
print(getattr(s1,"name123")) # 找不到报错
print(getattr(s1,"name123",None)) # 能够设置返回值则不报错
del s1.name           # 方式1
print(s1.__dict__)
delattr(s1,"name")     # 方式2
print(s1.__dict__)
setattr(s1,"age",10000) # 设置一个东西
print(s1.__dict__)
反射函数的用法

  为何用到反射(举个简单的小例子)服务器

    有俩程序员,一个alex,一个是egon,alex在写程序的时候须要用到egon所写的类,可是egon去跟女友度蜜月去了,尚未完成他写的类,alex想到了反射,使用了反射机制alex能够继续完成本身的代码,等egon度蜜月回来后再继续完成类的定义而且去实现alex想要的功能。网络

    总之反射的好处就是,能够事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这实际上是一种‘后期绑定’,什么意思?即你能够事先把主要的逻辑写好(只定义接口),而后后期再去实现接口的功能app

?
1
2
3
4
5
class FtpClient:
     'ftp客户端,可是还么有实现具体的功能'
     def __init__( self ,addr):
         print ( '正在链接服务器[%s]' % addr)
         self .addr = addr
#from module import FtpClient
f1=FtpClient('192.168.1.1')
if hasattr(f1,'get'):
    func_get=getattr(f1,'get')
    func_get()
else:
    print('---->不存在此方法')
    print('处理其余的逻辑')

不影响alex的代码编写

  三个参数,给对象添加属性ide

    这是python解释器底层的内置方法。固然咱们也能够对它们进行一些操做函数

    __setattr__   添加/修改属性会触发它的执行post

    __delattr__  删除属性的时候会触发spa

    __getattr__   只有在使用点调用属性且属性不存在的时候才会触发

    做用:系统内置函数属性(你定义了就用你定义的函数属性,不定义就用系统默认的函数属性)

class Foo:
    x=1
    def __init__(self,y):
        self.y=y

    def __getattr__(self, item):
        print('----> from getattr:你找的属性不存在')


    def __setattr__(self, key, value):
        print('----> from setattr')
        # self.key=value #这就无限递归了,你好好想一想
        # self.__dict__[key]=value #应该使用它

    def __delattr__(self, item):
        print('----> from delattr')
        # del self.item #无限递归了
        self.__dict__.pop(item)

#__setattr__添加/修改属性会触发它的执行
f1=Foo(10)
print(f1.__dict__) # 由于你重写了__setattr__,凡是赋值操做都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操做属性字典,不然永远没法赋值
f1.z=3
print(f1.__dict__)

#__delattr__删除属性的时候会触发
f1.__dict__['a']=3#咱们能够直接修改属性字典,来完成添加/修改属性的操做
del f1.a
print(f1.__dict__)

#__getattr__只有在使用点调用属性且属性不存在的时候才会触发
f1.xxxxxx
综合示例
class Foo:
    x=1
    def __init__(self,y):
        self.y=y

    def __getattr__(self, item):                   # __getattr__经常使用,且须要记忆
        print('执行__getattr__')

f1=Foo(10)
print(f1.y)

#没有的时候就会触发: __getattr__
print(getattr(f1,'y'))  #len(str)---->str.__len__()
f1.ssssssssssssssssssssssssssssss

10
10
执行__getattr__

  动态导入模块

  一、新建一个t.py的文件

print('---------------->')
def test1():
    print('test1')

def _test2():
    print('test2')

  二、再建立:m1文件夹,再在他下面建立一个t.py

module_t=__import__('m1.t')
print(module_t)
module_t.t.test1()
# from m1.t import *
# from m1.t import test,_test2

import importlib
m=importlib.import_module('m1.t')
print(m)
m.test1()
m._test2()
---------------->
<module 'm1' (namespace)>
test1
<module 'm1.t' from 'D:\\python\\day26\\m1\\t.py'>
test1
test2
输出

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

    包装:python为你们提供了标准数据类型,以及丰富的内置方法,其实在不少场景下咱们都须要基于标准数据类型来定制咱们本身的数据类型,新增/改写方法,这就用到了咱们刚学的继承/派生知识(其余的标准类型都可以经过下面的方式进行二次加工)

 1 # 二次加工标准类型
 2 class List(list):
 3     def append(self,p_object):
 4         if type(p_object) is str:
 5             super().append(p_object)
 6         else:
 7             print("添加的类型必须为字符串类型")
 8 
 9 l = List(["hello","world"])
10 l.append(1)
11 print(l)
12 
13 class Me(list):
14     def remove(self,value):
15         print("什么都不能删除")
16 
17 m = Me([1,2,3,4])
18 m.remove(2)
例子,对追加和删除的二次加工

  受权

    受权是包装的一个特性, 包装一个类型一般是对已存在的类型的一些定制,这种作法能够新建,修改或删除原有产品的功能。其它的则保持原样。受权的过程,便是全部更新的功能都是由新类的某部分来处理,但已存在的功能就受权给对象的默认属性。

    实现受权的关键点就是覆盖__getattr__方法

class Filehandle:
    def __init__(self,filename,mode="r",encoding="utf-8"):
        self.file = open(filename,mode,encoding=encoding)
        self.mode = mode
        self.encoding = encoding

    def __getattr__(self, item):
        print(item,type(item)) # read <class 'str'>
        self.file.read()  # self.file 里面有read方法
        return self.file,item

f1=Filehandle('a.txt','r')
# print(f1.file)     #  <_io.TextIOWrapper name='a.txt' mode='r' encoding='utf-8'>
print(f1.__dict__)   # 对象的属性字典中没有read方法,触发__getattr__方法
#{'file': <_io.TextIOWrapper name='a.txt' mode='r' encoding='utf-8'>, 'encoding': 'utf-8', 'mode': 'r'}
print(f1.read)       # 从而找到read方法

sys_F = Filehandle("b.txt","w+") # 从Filehandle中建立实例
print('---->',getattr(sys_F,'read')) 
# ----> (<_io.TextIOWrapper name='b.txt' mode='w+' encoding='utf-8'>, 'read')
文件下的受权
import time
class Filehandle:
    def __init__(self,filename,mode="r",encoding="utf-8"):
        self.file = open(filename,mode,encoding=encoding)
        self.mode = mode
        self.encoding = encoding
    def write(self,line):
        print("--------> ",line) # 输出打印的内容
        t = time.time()
        t = time.strftime('%Y-%m-%d %X') 
        self.file.write("%s %s" %(t,line)) # self.file 也有写的方法。

    def __getattr__(self, item):
    #     print(item,type(item)) # read <class 'str'>
    #     self.file.read()  # self.file 里面有read方法
        return self.file,item

f1=Filehandle('a.txt','r')
# print(f1.file)     #  <_io.TextIOWrapper name='a.txt' mode='r' encoding='utf-8'>
print(f1.__dict__)   # 对象的属性字典中没有read方法,触发__getattr__方法
#{'file': <_io.TextIOWrapper name='a.txt' mode='r' encoding='utf-8'>, 'encoding': 'utf-8', 'mode': 'r'}
print(f1.read)       # 从而找到read方法

sys_F = Filehandle("b.txt","w+") # 从Filehandle中建立实例
# print('---->',getattr(sys_F,'read'))
# ----> (<_io.TextIOWrapper name='b.txt' mode='w+' encoding='utf-8'>, 'read')

sys_F.write("路飞\n")
sys_F.write("娜美\n")
文件读写的受权

   类的特殊成员

class Foo:
    def __init__(self):
        print("我是init")
    def __call__(self, *args, **kwargs):
        print("我是call")
        return 1
# r = Foo()  类的实例化,执行init方法
# r() 对象加括号什么鬼?   实际上是调用了__call__
print(Foo()()) 

我是init
我是call
1
__call__

 

class Foo:
    def __init__(self):
        pass
    def __call__(self, *args, **kwargs):
        pass
    def __getitem__(self, item):
        print(item)
    def __setitem__(self, key, value):
        print(key,value)
    def __delitem__(self, key):
        print(key)
r = Foo()  #类的实例化,执行init方法
r() #对象加括号什么鬼?   实际上是调用了__call__
# print(Foo()())

r["getitem"] # __getitem__   
r["gs"] = 123 # __setitem__
del r["gs"] # __delitem__

getitem
gs 123
gs
__getitem__  __setitem__  __delitem__

   对三者的补充,再经过对列表索引切片的时候,查看,赋值,删除也是对应执行它们。

   经过字典的操做的方式是调用它们,而经过点的方式去取值是调用attr这些

#例子2
class Bar:
    def __init__(self):
        pass
    def __getitem__(self, item):
        print("__getitem__",item)
    def __setitem__(self, key, value):
        print("__setitem__")
        self.__dict__[key] = value
    def __delitem__(self, key):
        print("__delitem__")
        self.__dict__.pop(key)
b = Bar()
b["name"] = "alex"
print(b.__dict__)
del b["name"]
print(b.__dict__)
print(b["name"])


__setitem__
{'name': 'alex'}
__delitem__
{}
__getitem__ name
None
__getitem__,__setitem__,__delitem__

 

获取类或者对象里面的全部字段

例子未补充
__dict__

 

class C:
    def __init__(self,n):
        self.n = n
    def __iter__(self):
        return self
    def __next__(self):
        if self.n == 13:
            raise StopIteration
        self.n += 1
        return self.n
c = C(10)

for i in c: # for循环的强大机制,捕捉到StopIteration会结束  c.__iter__()
    print(i) # next(i) ----> i.__next__()
__iter__

 

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

class Sea(Onepiece):
    def __init__(self):
        pass
s = Sea()
o = Onepiece("路飞")
print(isinstance(o,Onepiece)) # 判断对象是否是该类下的
print(isinstance(s,Onepiece)) # 若是存在继承关系,则也是父类的对象

print(issubclass(Sea,Onepiece)) # 判断是否为子类
print(issubclass(Onepiece,Sea))
isinstance,issubclass

 

class Foo:
    x = 1
    def __init__(self,y):
        self.y = y

    def __getattr__(self, item):
        print("执行的是getattr",item)

    def __getattribute__(self, item):
        print("--->执行的是__getattribute__",item)
        raise AttributeError # 抛出一个异常交给__getattr__
    # 上面都是本身定义咱们想要的的机制过程,若是不写,系统也有一套系统默认的这种机制。

f = Foo(10)
f.xx

--->执行的是__getattribute__ xx           # 是大哥
执行的是getattr xx                                 # 是小弟
__getattr__,__getattribute__

   属性有没有都会触发__getattribute__

 1 class Fun:
 2     def __init__(self,name,age):
 3         self.name = name
 4         self.age = age
 5 
 6     # def __str__(self):
 7     #     return "%s %s " %(self.name,self.age)
 8     def __repr__(self):
 9         return "--->%s %s " %(self.name,self.age)
10 
11 me = Fun("Tom",18)
12 print(me) # 输出<__main__.Fun object at 0x000001AC455E7400>
13 # 若是加上__str__
14 print(me) # Tom 18
15 
16 # 若是__str__和__repr__都存在
17 print(me)  # str(me) >>> me.__str__() >>> me.__repr__()    顺序
18 # 若是__str__没有被定义,那么就会使用__repr__来代替输出
19 # 注意:这俩方法的返回值必须是字符串,不然抛出异常
__str__,__repr__

 

class Pinjie:
    def __init__(self,day,mouth,year):
        self.day = day
        self.mouth = mouth
        self.year = year

    def __format__(self, format_spec):
        return "{}-{}-{}" .format(self.mouth,self.day,self.year)

time = Pinjie(26,12,2017)
print(format(time))  # format()就是在执行__format__


# 也能够经过字典的方式进行指定格式。在这里写的比较硬
__format__

 

class A: # 定义__slots__以后 就没有了实例的属性字典
    __slots__ = "x"

a = A()
print(A.__dict__)
a.x = 2
a.y = 3  #报错


# __slots__ 称之为类字典,定义类变量以后,就没有了实例的属性字典,访问会报错
# 并且全部产生的实例都只有类变量下的东西,且不能再进行添加
# 好处:节省内存 弊端:失去扩展性
__slots__

 

输出文档注释信息,并且注释信息不能被继承
__doc__

 

1 # __moudle__ 获取当前导入的模块名
2 
3 # __class__ 获取类名 
__class__,__moudle__

 

class B:
    def __init__(self,name):
        self.name = name
    def __del__(self): # 析构方法,当结束运行,会执行析构方法。
        print("执行了!")

b = B("tom")
del b
print("---------->")


#析构方法,当对象在内存中被释放时,自动触发执行。
#注:此方法通常无须定义,由于Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,由于此工做都是交给Python解释器来执行,因此,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
__del__

 

#一、操做文件写法
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('=====>执行代码块')
    # print(f,f.name)
输出
出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
=====>执行代码块
with中代码块执行完毕时执行我啊

#三、执行代码块
__exit__()中的三个参数分别表明异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都没法执行

没有异常的状况下,整个代码块运行完毕后去触发__exit__,它的三个参数都会执行
class Foo:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print('执行enter')   
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('执行exit')
        print(exc_type)
        print(exc_val)
        print(exc_tb)
        

with Foo('a.txt') as f:
    print(f)             #<__main__.Foo object at 0x012E8A90>
    print(assfsfdsfd)  
    print(f.name)      
print('00000000')
输出
执行enter
Traceback (most recent call last):
<__main__.Foo object at 0x01478A90>
  File "D:/python/day28/s1.py", line 56, in <module>
执行exit
    print(assfsfd)   #触发__exit__
<class 'NameError'>
NameError: name 'assfsfd' is not defined
name 'assfsfd' is not defined
<traceback object at 0x01484710>

若是__exit()返回值为True,那么异常会被清空,就好像啥都没发生同样,with后的语句正常执行
#没有return True就会报错,若是有return True异常本身吃了,不报异常


#用途:
#1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工做,无须手动干预
#2.在须要管理一些资源好比文件,网络链接和锁的编程环境中,能够在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处
__enter__和__exit__

 

      未完待续……

相关文章
相关标签/搜索