14.继承与授权

反射
存在:hasatter(p,‘name‘)
获得:getattr
设置:setattr
小结练习:
反射的用途
反射实现可插拔机制
__setattr/delattr/getattr__
定制自己的数据类型
写一个自己的open
二次加工标准类型list
补充一点__getattribute__

反射

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

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

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
时间: 2024-08-09 22:02:27

14.继承与授权的相关文章

Java(14)继承

1.继承(extends) 1.1 继承:遗传 1.2 语法 public class 子类 extends 父类{ } public class Dog extends Pet{ } 1 public class Pet { 2 private String name = "无名氏"; 3 private int health = 90; 4 private int love = 0; 5 public Pet(){ 6 this.health = 95; 7 System.out.

C++学习14 继承的概念及语法

继承是类与类之间的关系,是一个很简单很直观的概念,与现实世界中的继承(例如儿子继承父亲财产)类似. 继承(Inheritance)可以理解为一个类从另一个类获取成员变量和成员函数的过程.例如类B继承于类A,那么B就拥有A的成员变量和成员函数.被继承的类称为父类或基类,继承的类称为子类或派生类. 派生类除了拥有基类的成员,还可以定义自己的新成员,以增强类的功能. 以下是两种典型的使用继承的场景:1) 当你创建的新类与现有的类相似,只是多出若干成员变量或成员函数时,可以使用继承,这样不但会减少代码量

swift 学习- 14 -- 继承

// 一个类可以继承另一个 类的方法, 属性和其他特征, 当一个类继承其他类时, 继承类叫子类, 被继承类叫父类 或 (超类), 在 Swift 中, 继承是区分 [类] 和其他类型的 一个基本特征 // 在 Swift 中, 类可以调用和访问超类的方法, 属性 和 下标, 并且可以重写这些方法, 属性 和 下标来优化或修改他们的行为 // Swift 会检查你的重写定义在超类中是否有匹配的定义, 一次确保你的重写行为是正确的 // 可以为类中继承来的属性添加属性观察器, 这样一来, 当属性值改

Javascript 继承的六种方法

1.原型链 利用原型让一个引用类继承另一个引用类型的属性和方法 1 function superType() { 2 this.property = true; 3 } 4 5 superType.prototype.getSuperValue = function () { 6 return this.property; 7 } 8 9 function subType() { 10 this.subProperty = false; 11 } 12 13 subType.prototype

SqlServer用户授权配置

1 --创建登录账户:用户默认为public角色 2 USE [master] 3 GO 4 CREATE LOGIN [登录名] WITH PASSWORD=N'密码', DEFAULT_DATABASE=[test], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF 5 GO 6 7 --删除登录账户(登录名不用引号,'[]'号为必须,防止用户为单纯的数字) 8 USE [master] 9 go 10 EXEC sys.sp_revokedbaccess @n

详细理解JS中的继承

正式说继承之前,有两个相关小点: JS只支持实现继承,即继承实际的方法,不支持接口继承(即继承方法的签名,但JS中函数没签名) 所有对象都继承了Object.prototype上的属性和方法. 说继承之前还要再说一下原型.原型之所以很重要,原因之一就是可以利用它来实现JavaScript的继承.重写一个函数的原型对象,将其指定为另一个函数的实例,这样便实现了一个简单的原型链继承. 看一个利用原型链来实现继承的基础例子: 1 function Super(){ 2 this.name='super

组合继承与寄生组合式继承

组合继承 将原型链和借用构造函数的技术组合到一块. 使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承. 超类的属性被继承了两次,一次是在子类的构造函数中,使得子类实例拥有各自的属性:一次是在子类的原型中,使得子类拥有相同的属性. 1 function SuperType(name){ 2 this.name = name; 3 this.colors = ["red","blue","green"]; 4 } 5 S

继承1.继承,2.属性查找顺序3.子类访问父类内容4.补充,经典类与新式类 --------- # 21

继承: 1.继承 1.1继承 1 '''''' 2 """ 3 1.什么是继承? 4 继承是描述两个对象之间,什么是什么的关系 5 6 案例:麦兜,佩奇,猪刚鬓 -- 都是猪 7 8 在程序中,继承描述的是类和类之间的关系 9 10 例如:a 继承 b,a就能直接使用b已经存在的方法或属性 11 此时,a称之为子类,b被称之为父类,也称为基类 12 13 2.为什么要使用继承? 14 继承的一方制剂使用另一方已经有的东西 15 其目的是:提高重用性(重用已有的代码) 16 1

Java——类、对象与继承

今天我们谈的是――类与对象.类的继承. 2019-08-25 17:22:35 目录怎样定义类,对象又是什么?类在Java中有什么存在的意义?继承在Java中有何重要意义?继承了什么? 类.对象 要理解类的定义,我们首先来了解一下对象是什么.所谓对象,就是现实生活中真真实实存在的事物,例如这个鼠标,这个学生,这个茶杯等等…而类就是对这些真实存在的事物进行一个抽象.我们把具有相同特征的一些对象抽象成为同一个复本,那么这个复本就叫作类.类具有这些对象的相同特征.例如学生这个类(因为不是特指,所以是类