Python学习笔记-面向对象进阶(二)

一、反射

1、什么是反射

  反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。

2、Python面向对象中的反射

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

3、四个可以实现自省的函数

(1)hasattr(object,name),判断object中有没有一个name字符串对应的方法或属性,检测是否含有某属性。

class BlackMedium:
    feture=‘Ugly‘
    def __init__(self,name,addr):
        self.name=name
        self.addr=addr

    def sell_hourse(self):
        print(‘【%s】正在卖房子,傻逼才买呢‘ %self.name)

    def rent_hourse(self):
        print(‘【%s】正在租房子,傻逼才租呢‘ %self.name)

b1=BlackMedium(‘黑中介‘,‘北京‘)
print(hasattr(b1,‘name‘))
print(hasattr(b1,‘sell_hourse‘))
"""
True
True
"""

hasattr(object,name)

(2)getattr(object, name, default=None),获取属性。

class BlackMedium:
    feture=‘Ugly‘
    def __init__(self,name,addr):
        self.name=name
        self.addr=addr

    def sell_hourse(self):
        print(‘【%s】正在卖房子,傻逼才买呢‘ %self.name)

    def rent_hourse(self):
        print(‘【%s】正在租房子,傻逼才租呢‘ %self.name)

b1=BlackMedium(‘黑中介‘,‘北京‘)
print(getattr(b1,‘name‘))
print(getattr(b1,‘rent_hourse‘))
fun=getattr(b1,‘rent_hourse‘)
fun()
# print(getattr(b1,‘aaaaa‘)) # 没有aaaaa这个属性则报错
print(getattr(b1,‘aaaaa‘,‘没有这个属性‘)) # 没有aaaaa这个属性则输出“没有这个属性”

"""
黑中介
<bound method BlackMedium.rent_hourse of <__main__.BlackMedium object at 0x101d3fba8>>
【黑中介】正在租房子,傻逼才租呢
没有这个属性
"""

getattr(object, name, default=None)

(3)setattr(x, y, v),设置属性。

class BlackMedium:
    feture=‘Ugly‘
    def __init__(self,name,addr):
        self.name=name
        self.addr=addr

    def sell_hourse(self):
        print(‘【%s】正在卖房子,傻逼才买呢‘ %self.name)

    def rent_hourse(self):
        print(‘【%s】正在租房子,傻逼才租呢‘ %self.name)

b1=BlackMedium(‘黑中介‘,‘北京‘)
setattr(b1,‘sb‘,True) # b1.sb=True
setattr(b1,‘sb1‘,123) # b1.sb=True
print(b1.__dict__)

"""
{‘name‘: ‘黑中介‘, ‘addr‘: ‘北京‘, ‘sb‘: True, ‘sb1‘: 123}
"""

setattr(x, y, v)

(4)delattr(x, y),删除属性。

class BlackMedium:
    feture=‘Ugly‘
    def __init__(self,name,addr):
        self.name=name
        self.addr=addr

    def sell_hourse(self):
        print(‘【%s】正在卖房子,傻逼才买呢‘ %self.name)

    def rent_hourse(self):
        print(‘【%s】正在租房子,傻逼才租呢‘ %self.name)

b1=BlackMedium(‘黑中介‘,‘北京‘)
setattr(b1,‘sb‘,True) # b1.sb=True
setattr(b1,‘sb1‘,123) # b1.sb=True
delattr(b1,‘sb‘) # del b1.sb
delattr(b1,‘sb1‘) # del b1.sb1
print(b1.__dict__)

"""
{‘name‘: ‘黑中介‘, ‘addr‘: ‘北京‘}
"""

delattr(x, y)

4、为什么要使用反射?

(1)“即插即用”:可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能。

(2)动态导入模块(基于反射当前模块成员)

二、__setattr__,__delattr__,__getattr__

1、__getattr__含义是只要找的属性不存在就会触发__getattr__

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

    def __getattr__(self, item):
        print(‘你要找的属性不存在‘)

f1=Foo(10)
print(f1.y)
f1.aaaaaa
"""
10
你要找的属性不存在
"""

__getattr__

2、__delattr__含义是执行删除操作的时候出发__delattr__

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

    def __delattr__(self, item):
        self.__dict__.pop(item)
        print(‘删除操作‘)

f1=Foo(10)
f1.__dict__[‘z‘]=3
print(f1.__dict__)
del f1.y
print(f1.__dict__)
"""
{‘y‘: 10, ‘z‘: 3}
删除操作
{‘z‘: 3}
"""

__delattr__

3、__setattr__含义是添加/修改属性会触发它的执行

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

    def __setattr__(self, key, value):
        print(‘__setattr__执行‘)
        # self.key=value # 这样就会无限递归了
        self.__dict__[key]=value # 直接修改底层字典
f1=Foo(10)
print(f1.__dict__)
f1.z=2
print(f1.__dict__)
"""
__setattr__执行
{‘y‘: 10}
__setattr__执行
{‘y‘: 10, ‘z‘: 2}
"""

__setattr__

4、__getattr__补充

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

    def __getattr__(self, item):
        print(‘你找的属性【%s】不存在‘ %item)

f1=Foo(‘lionel‘)
print(f1.name)
print(f1.age)
print(f1.sex)
"""
lionel
你找的属性【age】不存在
None
你找的属性【sex】不存在
None
"""

__getattr__补充item

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

1、包装

  python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法。

class List(list): # 继承list所有的属性,也可以派生出自己新的,比如append和pop
    def append(self, p_object):
        ‘派生自己的append:加上类型检查‘
        if type(p_object) is str:
            super().append(p_object)
        else:
            print(‘只能添加字符串类型‘)

l1=list(‘hello world‘)
print(l1,type(l1))
"""
[‘h‘, ‘e‘, ‘l‘, ‘l‘, ‘o‘, ‘ ‘, ‘w‘, ‘o‘, ‘r‘, ‘l‘, ‘d‘] <class ‘list‘>
"""

l2=List(‘hello world‘)
print(l2,type(l2))
"""
[‘h‘, ‘e‘, ‘l‘, ‘l‘, ‘o‘, ‘ ‘, ‘w‘, ‘o‘, ‘r‘, ‘l‘, ‘d‘] <class ‘__main__.List‘>
"""

l2.append(‘aaaaa‘)
print(l2)
"""
[‘h‘, ‘e‘, ‘l‘, ‘l‘, ‘o‘, ‘ ‘, ‘w‘, ‘o‘, ‘r‘, ‘l‘, ‘d‘, ‘aaaaa‘]
"""

l2.append(123123123)
print(l2)
"""
只能添加字符串类型
[‘h‘, ‘e‘, ‘l‘, ‘l‘, ‘o‘, ‘ ‘, ‘w‘, ‘o‘, ‘r‘, ‘l‘, ‘d‘, ‘aaaaa‘]
"""

包装标准类型

2、授权

  授权是包装的一个特性,包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能,其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。实现授权的关键点就是覆盖__getattr__方法。

import time
class FileHandle:
    def __init__(self,filename,mode=‘r‘,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):
        # print(item)
        return getattr(self.file,item)

while True:
    info=input(‘>>: ‘)
    f1.write(‘%s\n‘ %info)

# a.txt文件内容
"""
2018-04-20 18:06:15 cpu负载过高
2018-04-20 18:06:15 内存剩余不足
2018-04-20 18:06:15 硬盘剩余不足
2018-04-20 18:06:38 mysql集群宕机
2018-04-20 18:06:48 kvm虚拟机故障
2018-04-20 18:07:17 数据库被删除
"""

授权

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

1、isinstance(obj,cls)检查是否obj是否是类cls的对象

class Foo:
    pass

f1=Foo()
print(isinstance(f1,Foo))
"""
True
"""

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

class Bar(Foo):
    pass

print(issubclass(Bar,Foo))
"""
True
"""

五、__getattribute__(self, item)

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

    def __getattr__(self, item):
        print(‘执行的是__getattr‘)
        # return self.__dict__[item]

f1=Foo(10)
print(f1.x)
f1.xxxxxx
"""
10
执行的是__getattr
"""

__getattr__(self, item)

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

    # 不管找不找得到属性,都会触发__getattribute__
    def __getattribute__(self, item):
        print(‘执行的是__getattribute__‘)
        raise AttributeError(‘抛出异常‘)

f1=Foo(10)
f1.x
f1.xxxxxx

__getattribute__(self, item)

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

    def __getattr__(self, item):
        print(‘执行的是__getattr__‘)
        # return self.__dict__[item]

    # 不管找不找得到属性,都会触发__getattribute__
    def __getattribute__(self, item):
        print(‘执行的是__getattribute__‘)
        raise AttributeError(‘抛出异常‘)

f1=Foo(10)
f1.x
f1.xxxxxx
"""
执行的是__getattribute__
执行的是__getattr__
执行的是__getattribute__
执行的是__getattr__
"""

__getattr__和__getattribute__同时存在

总结

  当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError,才会执行__getattr__。

六、__setitem__,__getitem,__delitem__

# 中括号形式调用就是*item方法,点的形式调用就是*attr方法
class Foo:
    def __getitem__(self, item):
        print(‘getitem‘,item)
        return self.__dict__[item]

    def __setitem__(self, key, value):
        print(‘setitem‘)
        self.__dict__[key] = value

    def __delitem__(self, key):
        print(‘delitem‘)
        self.__dict__.pop(key)

f1=Foo()
f1[‘name‘] = ‘lionel‘
f1[‘age‘] = ‘18‘
print(f1.__dict__)
"""
setitem
setitem
{‘name‘: ‘lionel‘, ‘age‘: ‘18‘}
"""

del f1[‘name‘]
print(f1.__dict__)
"""
delitem
{‘age‘: ‘18‘}
"""

print(f1[‘age‘])
"""
getitem age
18
"""

七、__str__与__repr__改变对象的字符串显示

1、改变对象的字符串显示

  改变对象的字符串显示__str__,__repr__ 。 __str__在print时触发,__repr__在解释器中触发。

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(‘lionel‘,18)
print(f1) # str(f1) ---> f1.__str__()
"""
名字是lionel 年龄是18
"""

__str__

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

    def __str__(self):
        return ‘这是str‘

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

f1=Foo(‘lionel‘,20)
print(f1) # str(f1) ---> f1.__str__() ,如果找不到str就会找repr   repr(f1) ---> f1.__repr__()
"""
这是str
"""

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

__str__和__repr__

八、自定义格式化方式__format__

format_dic={
    ‘ymd‘:‘{0.year}{0.mon}{0.day}‘,
    ‘y-m-d‘:‘{0.year}-{0.mon}-{0.day}‘,
    ‘y:m:d‘:‘{0.year}:{0.mon}:{0.day}‘,
    ‘default‘:‘{0.year}_{0.mon}_{0.day}‘
}

class Date:
    def __init__(self,year,mon,day):
        self.year=year
        self.mon=mon
        self.day=day

    def __format__(self, format_spec):
        print(‘我执行啦‘)
        if not format_spec or format_spec not in format_dic:
            format_spec=‘default‘
        fm=format_dic[format_spec]
        return fm.format(self)

d1=Date(2018,4,21)

print(format(d1,‘ymd‘)) # 2018421
print(format(d1,‘y-m-d‘)) # 2018-4-21
print(format(d1,‘y:m:d‘)) # 2018:4:21
print(format(d1)) # 2018_4_21
print(format(d1,‘asd‘)) # 2018_4_21
"""
我执行啦
2018421
我执行啦
2018-4-21
我执行啦
2018:4:21
我执行啦
2018_4_21
我执行啦
2018_4_21
"""

__format__

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

class Range:
    def __init__(self,n,stop,step):
        self.n=n
        self.stop=stop
        self.step=step

    def __next__(self):
        if self.n >= self.stop:
            raise StopIteration
        x=self.n
        self.n+=self.step
        return x

    def __iter__(self):
        return self

for i in Range(1,7,3):
    print(i)
"""
/usr/local/bin/python3 /Users/wangzhiwei/python/day7/13_迭代器协议.py
1
4
"""

迭代器协议

class Fib:
    def __init__(self):
        self._a=1
        self._b=1

    def __iter__(self):
        return self

    def __next__(self):
        if self._a > 100:
            raise StopIteration(‘终止了‘)
        self._a,self._b = self._b,self._a + self._b
        return self._a

f1=Fib()
for i in f1:
    print(i)
"""
1
2
3
5
8
13
21
34
55
89
144
"""

迭代器协议实现斐波那契数列

十、描述符(__get__,__set__,__delete__)

1、描述符是什么?

  描述符本质就是一个新式类,在这个新式类中,至少实现了__get__()、__set__()、__delete__()中的一个,这也被称为描述符协议。
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发

2、描述符是干什么的?

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

class Foo:
    def __get__(self, instance, owner):
        print(‘===>get方法‘)
    def __set__(self, instance, value):
        print(‘===>set方法‘)
    def __delete__(self, instance):
        print(‘===>delete方法‘)

class Bar:
    x=Foo()

b1=Bar()
b1.x
"""
===>get方法
"""
# __get__():调用一个属性时,触发
# __set__():为一个属性赋值时,触发
# __delete__():采用del删除属性时,触发

十一、上下文管理协议(__enter__和__exit__)

1、什么是上下文管理协议

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

class Open:
    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‘)

with Open(‘a.txt‘) as f:
    print(‘=====>‘)
    print(f)
    print(f.name)

print(‘00000000000‘)
"""
执行enter
=====>
<__main__.Open object at 0x10353f9b0>
a.txt
执行exit
00000000000
"""

# with obj as f:
#     ‘代码块‘
# 1、with obj --->触发obj.__enter__(),拿到返回值
# 2、as f ---->f=返回值
# 3、with obj as f  等同于  f = obj.__enter__()
# 4、执行代码块
# 一:没有异常的情况下,整个代码块运行完毕后去触发__exit__,它的三个参数都为None
# 二:有异常的情况下,从异常出现的位置直接触发__exit__
#     a:如果__exit__的返回值为True,代表吞掉了异常
#     b:如果__exit__的返回值不为True,代表吐出了异常
#     c:__exit__的运行完毕就代表了整个with语句的执行完毕

2、使用场景

  • 使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
  • 在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处

十二、类的装饰器

def deco(obj):
    print(‘=======‘)
    return obj

@deco
def test():
    print(‘test函数运行‘)
test()
"""
=======
test函数运行
"""

def deco(obj):
    print(‘=======‘)
    obj.x=1
    obj.y=2
    obj.z=3
    return obj

@deco
class Foo():
    pass

f1=Foo()
print(Foo.__dict__)
print(f1.x)
"""
=======
{‘__module__‘: ‘__main__‘, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Foo‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Foo‘ objects>, ‘__doc__‘: None, ‘x‘: 1, ‘y‘: 2, ‘z‘: 3}
1
"""

def Typed(**kwargs):
    def deco(obj):
        for key,val in kwargs.items():
            setattr(obj,key,val)
        return obj
    print(‘===>‘,kwargs)
    return deco

@Typed(x=1,y=2,z=3)
class Foo():
    pass
print(Foo.__dict__)

@Typed(name=‘lionel‘)
class Bar:
    pass
b1=Bar()
print(b1.name)
"""
===> {‘x‘: 1, ‘y‘: 2, ‘z‘: 3}
{‘__module__‘: ‘__main__‘, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Foo‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Foo‘ objects>, ‘__doc__‘: None, ‘x‘: 1, ‘y‘: 2, ‘z‘: 3}
===> {‘name‘: ‘lionel‘}
lionel
"""

类的装饰器增强版

原文地址:https://www.cnblogs.com/wangzhiwei10/p/8989992.html

时间: 2024-09-30 14:23:11

Python学习笔记-面向对象进阶(二)的相关文章

Python学习笔记-面向对象进阶(一)封装、多态、继承

一.初识继承 1.什么是继承? 继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类或超类,新建的类称为派生类或子类.子类会"遗传"父类的属性,从而解决代码重用问题. # python中类的继承分为:单继承和多继承 class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1

Python学习笔记-面向对象

一.什么是面向对象的程序设计 1.面向过程的程序设计 面向过程:核心是过程二字,过程即解决问题的步骤,就是先干什么,再干什么.基于该思想写程序就好比在设计一条流水线,是一种机械式的思维方式. 优点:复杂的过程流程化,进而简单化 缺点:扩展性差 2.面向对象的程序设计 面向对象:核心是对象二字,对象是特征与技能的结合体.基于该思想编写程序就好比在创造一个世界,世界是由一个个对象组成,是一种"上帝式"的思维方式 优点:可扩展性强 缺点:编程复杂度高,容易出现过度设计问题 二.类与对象 对象

Python学习之面向对象进阶

面向对象进阶当然是要谈谈面向对象的三大特性:封装.继承.多态 @property装饰器 python虽然不建议把属性和方法都设为私有的,但是完全暴露给外界也不好,这样,我们给属性赋值的有效性九无法保证,因此,为了使得对属性的访问既安全又方便,可以通过属性的getter(访问器)和setter(修改器)方法进行对应的操作,在python中,可以考虑使用@property包装器来包装getter和setter方法 class Person(object): def __init__(self,nam

Python 学习笔记 - 面向对象(类成员)

上一篇学习了Python面向对象的3大特性,封装,继承和多态,这一篇继续学习类成员,包括字段,方法,属性以及他们的修饰符. 1.字段 字段分为静态字段和普通字段.静态字段属于类,而普通字段属于对象,因此静态字段在内存中只保存一份,而普通字段在每个对象中都保存了一份.定义的时候静态字段定义在类的范围里面,而普通字段定义在方法里面. 例如: >>> class Foo:     # 字段(静态字段)     CC = 123     def __init__(self):         #

Python 学习笔记 - 面向对象(基础)

之前学习的编程方式都是通过面向过程来实现的,对于一些重用的代码,进一步的使用了函数,增强了代码的可读性和重用性.Python同时还支持面向对象的编程. 面向对象有三大特性: 封装 继承 多态 首先来看看封装.封装包括两点,把内容封装到某个地方:调用封装的内容 例1: class c1:     def __init__(self,name,obj):         self.name = name         self.obj = obj class c2:     def __init_

python学习笔记--面向对象的编程和类

一.面向对象的编程 面向对象程序设计--Object Oriented Programming,简称oop,是一种程序设计思想.二.面向对象的特性类:class类,对比现实世界来说就是一个种类,一个模型.一个类即是对一类拥有相同属性的对象的抽象.蓝图.原型.在类中定义了这些对象的都具备的属性(variables(data)).共同的方法. 对象:object对象,也就是指模型造出来的具体的东西.一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每

Python学习笔记——面向对象编程

接下来学习面向对象编程,基础的就不记录了,只记录一些Python特有的或者高级的特性. http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318645694388f1f10473d7f416e9291616be8367ab5000 1. 类的定义 定义类使用class关键字,后面紧跟类名(首字母大写),接着是从哪个类继承下来的(所有类最终会继承object). 通过类名加参

python学习_day28_面向对象进阶

一.内置函数isinstance和issubclass 1.isinstance() isinstance(obj,cls)检查obj是否是类 cls 的对象,类似type(). class Foo(object): pass obj = Foo() print(isinstance(obj, Foo)) #输出结果:True print(isinstance(10,int)) #输出结果:True sinstance() 与 type() 区别:type() 不会认为子类是一种父类类型,不考虑

python学习总结(面向对象进阶)

-------------------类属性和实例属性关系------------------- 1.类属性和实例属性关系 1.实例属性 实例对象独有的属性 2.类属性 类名访问类属性 3.实例中无同名属性时,可访问到类属性,当定义同名实例属性时,则无法访问 4.常用的查找指令 1.vars :查看实例内属性 2.dir :显示类属性和所有实例属性 3.type :显示类型 -------------------方法------------------- 1.实例方法 隐含的参数为类实例self