14. 继承与授权

[TOC]

反射

自省:程序能够访问,检测和修改他本身的状态或者行为的能力

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

class people:
    country = 'China'
    def __init__(self,name):
        self.name = name

p = people('scott')
people.country
print(people.__dict__)

存在:hasatter(p,'name')

p这个对象下,有没有‘name’这个属性
其实就是
print('name' in p.__dict__)
返回一个bool值

获得:getattr

p这个对象下,调用country参数
gatattr(p,'country')
等同于
p.country

def getattr(object, name, default=None): # known special case of getattr
    """
    getattr(object, name[, default]) -> value

    Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
    When a default argument is given, it is returned when the attribute doesn't
    exist; without it, an exception is raised in that case.
    """
    pass

设置:setattr

setattr(p,'country','China')
等同于
p.country = 'China'

提问:

>>> l = [1,2,4,5,8]
>>> setattr(l,'append','China')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object attribute 'append' is read-only

小结练习:

class People:#定义一个类
    def __init__(self,name):
        self.name = name#提供一个绑定参数

p1 =People('scott')#实例化p1
p2 =People('jerry')#实例化p2
#给p1对象添加一个‘country’属性,值为‘China’
setattr(p1,'country','China')
#使用getattr获取这个属性并且打印
print(getattr(p1,'country'))
#以上那个country参数,是我添加给对象p1的,查看p2是否也获得了这个参数?-----并没有,这个参数单独被加在p1这个对象中
print(hasattr(p2,'country'))
# 使用delattr删除刚才添加的country参数
delattr(p1,'country')
#检查
hasattr(p1,'country')
#定义一个函数func
def func(self):
    print(self.name,' like python')
#利用lambda给p1对象传入一个work方法
setattr(p1,'work',lambda self: (self.name,'like python') )
#给p1传入func方法
setattr(p1,'work2',func )
#目前两个work方法均是针对p1传值的,但是在下方实例化p1的work2方法为h,并且对两个对象进行work2方法,发现两个对象均可以使用
#设置setattr可以将一个函数或者参数指向添加给某个对象的类
#虽然在设置中,设置的P1但是其实和p1同类的实例均可以调用

print(hasattr(p1,'work'))

g = getattr(p1,'work')
h = getattr(p1,'work2')
print(g(p1))
h(p1)
h(p2)

反射的用途

反射当前模块的属性

import sys
#导入系统模块
x = 1111
class foo:
    pass
def s1():
    print('s1')
def s2():
    print('s2')
this_module = sys.modyles[__name__]
#将当前写的程序作为一个模块“this_module”
def add():
    print('add')

def change():
    print('change')

def search():
    print('search')

def delete():
    print('delete')

func_dic = {
    'add':add
    'change':change
    'search':search
    'delete':delete
}
  • 方法一(常规)
while True:
    cmd = input('>>:')
    if not cmd:continu
    if cmd in func_dic:        #hasattr()
        func= func_dic.get(cmd)    #gatattr()
        func()
  • 方法二(利用反射实现)
this_module = sys.modyles[__name__]
#将以上程序归为一个模块,命名为this_module
while True:
    cmd = input('>>>').strip()
    if not cmd:continu
    if hasatter(this_module,cmd):
        func = getattr(this_module,cmd)
        func()

反射实现可插拔机制

  • server
from ftp_1 import FtpClient
#从FIP_1中载入FtpClient模块
f1 = FtpClient('192.168.1.1')
#实例化
if hasattr(f1,'get'):
#查看能不能从对象中获取一个‘get’函数
    func_get = getattr(f1,'get')
    func_get()#如果能获取就运行
else:
#如果没有就打出标志位
    print('---------->')

在上述程序中,如果在FtpClient文件中没有定义一个get函数。并不会影响上述程序执行。但是如果FtpClient文件补全了了这个get函数,上述文件并不需要修改,就能正常实现功能

  • ftp module
#提供一个FtpClient类
class FtpClient:
    def __init__(self,addr):
        print('lianjie [%s]'%addr)
        self.addr = addr

通过字符串导入模块

m = input('module:')
m1 = __import__(m)
print(m1)
print(m1.time())

推荐使用以下方法

import importlib
t = importlib.import_module('time')
print(t.time())

_setattr/delattr/getattr_

下面这段代码,串讲一些之前提到的setattr、delattr、getattr,并且介绍setattr/delattr/getattr

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

实现授权的关键点就是覆盖getattr方法

class Foo:
    def __init__(self,name):
        self.name = name
    def __setattr__(self,key,value):
        print('----setattr----'key,value)
    #由于传入的key和value都是字符串,不能直接跟在self后面
    #self.key = value
    #setattr(self,key,value)#同上
    #在当前函数中设置这个赋值(因为重写了__setattr__,所有的赋值操作都会指向这个函数运行),就相当于把这个函数变成一个无限递归。
    #正确的方法应该是,直接操作__dict__
    self.__dict__[key] = value

    def __delattr__(self,item):
        print('delattr:%s'%item)
        print(type(item))
        # delattr(self,item)
        # del self.item
        self.__dict__.pop(item)
        #原理同上,为了防止递归和字符串类型干扰,应该直接操作__dict__

    def __getattr__(self,item);
        print('get------>%s  %s'%(item,type(item)))

f = Foo('scott')
print(f.name)
#当一个属性存在的时候,正常寻找self.name
print(f.xxxxx)
#当属性不存在的时候,才触发__geattr__


f1 = Foo('egon')
f1.age = 18

print(f1.__dict__)

字典为空,之前的两次传入调用参数,都直接进入了setattr

定制自己的数据类型

写一个类,继承原来的list类

class List(list):
    def append(self,p_object):
        if not isinstance(p_object,int):
            raise TypeError('str')
        super().append(p_object)

写一个自己的open

由于open是一个函数,所以不能直接继承

import time

class Open:
    def __init__(self,filepath,m = 'r',encode = 'utf8'):
        self.x= open(filepath,mode = m,encoding = 'utf8')
        #以上self.x就是一个文件句柄,之后需要原文件操作类赋予的动作均使用这个句柄来进行。
        self.mode = m
        self.encoding = encode

    def write(self,line):
        print('time',line)
        self.x.write(time.strftime('%Y-%m-%d %X'),line)

    #授权得分
    def __getattr__(self,item):
        print('--->',item,type(item))
        getattr(self.x,item)
    #在当前类找不到某个方法的时候,因为self.x是一个可以调用各种文件操作的句柄,所以使用getattr方法,来获得这些方法,并且在上方提示。
    #有了这个函数定义之后,就可以在f中使用各个文件操作方式。

f =Open('b.txt','w+')
print(f)
f.write('111111111111')
print(f.read())
f.seek(0)

二次加工标准类型list

要求使用授权的方式:

'''
作业:
    基于授权定制自己的列表类型,要求定制的自己的__init__方法,
    定制自己的append:只能向列表加入字符串类型的值
    定制显示列表中间那个值的属性(提示:property)
    其余方法都使用list默认的(提示:__getattr__加反射)
'''
class List:
    def __init__(self,LOBJECT):
        #将self.x定义为list类包装过的传入参数LOBJECT,以此来获得list的一些方法
        self.x = list(LOBJECT)

    #重新定义append方法,使所有添加进来的参数均转换成str数据类型
    def append(self,value):
        print('后添加的元素都是str格式!')
        if not isinstance(value,str):
            self.x.append(str(value))
            # raise TypeError('ERROR')
        else:
            self.x.append(value)

    #特征化一个函数,这个函数会返回一个列表的中间值,如果这个列表的元素数量为偶数,就返回中间两个值。
    @property
    def mid_list(self):
        len_th =len(self.x)
        if len_th%2==0:
            f1 = self.x[(len_th//2)]
            f2 = self.x[(len_th//2)-1]
            return f1,f2
        else:
            return self.x[len_th // 2]
    #授权self.x获得其他没有定义的关于list的函数,因为传入的对象为self.x,它属于list类。
    def __getattr__(self, item):
        getattr(self.x,item)
    #为了让List对象在打印的时候也和list对象一样,一旦打印就能获得将传入数据类型变为list的能力,在这里使用__str__,使得每次传入的参数返回出来都是list
    def __str__(self):
        return str(self.x)

y = (4,5,7,8,6)

k = List((1,2,4,5,7))
l = List([1,2,3,4,5,6])
# print(l)
print(k)
print(List(y))
# l.append(12)
print(k.mid_list)

补充一点getattribute

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'

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

    def __getattr__(self, item):
        print('执行的是我')
        # return self.__dict__[item]
    def __getattribute__(self, item):
        print('不管是否存在,我都会执行')
        raise AttributeError('哈哈')

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

#当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,654评论 18 139
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,966评论 6 13
  • Python内置函数详解——总结篇 ** 引 言** ** 数学运算** abs:求数值的绝对值>>> abs...
    yutiansut阅读 734评论 0 1
  • 我是个情商低特别低的人,低到不会什么花言巧语哄女孩开心,看到女生当面哭,都不知道该怎么办,最多递上纸巾说一句:“别...
    Tom_说阅读 587评论 22 0
  • 这里是中国药都,全国最大的中药材贸易中心。 吃食,在哪里都有它与众不同的地方。哪怕这里小到你没有听过。 我喜欢的美...
    裸食阅读 801评论 0 5