python学习笔记(八)property装饰器真麻烦

获取对象信息

使用type()
首先,我们来判断对象类型,使用type()函数:
基本类型都可以用type()判断:

>>> type(123)
<class 'int'>
>>> type('str')
<class 'str'>
>>> type(None)
<type(None) 'NoneType'>

变量、函数、类也可以

>>> type(abs)
<class 'builtin_function_or_method'>
>>> type(a)
<class '__main__.Animal'>

并且让他判断什么类型,他返回的就是什么类型。
判断一个变量是否是函数:

>>> type(123)==type(456)
True
>>> type(123)==int
True
>>> type('abc')==type('123')
True
>>> type('abc')==str
True
>>> type('abc')==type(123)
False

判断一个对象是否是函数

>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType
True

使用 isinstance()
当继承关系是:
object->Animal->Dog->Husky
isinstance()可以测出 谁是谁的子类

class Animal(object):
    pass

class Dog(Animal):
    def  run(self):
        print("Dog is  running")
class Husky(Dog):
    def run(self):
        print('Husky is  slowly running')

a = Animal()
d = Dog()
h =  Husky()
x  = isinstance(h, Husky)
print(x)
x = isinstance(h, Dog)
print(x)

结果:
在这里插入图片描述
还可判断一个变量是否是某些类型的一种

>>> isinstance([1, 2, 3], (list, tuple))
True
>>> isinstance((1, 2, 3), (list, tuple))
True

也可以判断基本数据类型

总是优先使用isinstance()判断类型,可以将指定类型及其子类“一网打尽”。

dir()
如果获得一个对象所有的属性和方法 ,可以使用dir()函数

dir('ABC')
['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']

类似__xxx__的属性和方法在Python中都是有特殊用途的,比如__len__方法返回长度。在Python中,如果你调用len()函数试图获取一个对象的长度,实际上,在len()函数内部,它自动去调用该对象的__len__()方法,所以,下面的代码是等价的:

>>> len('ABC')
3
>>> 'ABC'.__len__()
3

lower()返回小写的字符串。
hasattr(实例名,实例属性名字符串),看实例中是否有这个属性,返回true或false。
setattr(实例名,实例属性名(原来有没有这个属性都可以),属性值),设置一个新的属性并为其赋值或者给原有属性赋新值。
getattr(实例名,实例属性名字符串),获取这个实例的这个属性的值。

可以传入一个default参数,如果属性不存在,就返回默认值:

>>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
404

获得实例 函数 的流程:

hasattr(obj, 'power')  #有power 这个东西吗
fn  = getattr(obj, 'power') #保存 power 函数到fn中去
fn()   #与调用obj.power()一样

例:

def readImage(fp):
    if hasattr(fp, 'read'):
        return readData(fp)
    return None

假设我们希望从文件流fp中读取图像,我们首先要判断该 fp对象是否 存在 read方法,如果存在,则该对象是一个流,如果不存在,就无法读取。
在动态语言python中,根据鸭子类型,有read()方法 不代表该fp对象就是一个文件流,也可能是网络流,也可能是内存中的一个字节流,但只要read()返回的是有效的图像数据,就不影响读取图像的功能。

实例属性和类属性

python是动态语言,根据类创建的实例可以任意绑定属性。
给实例绑定属性的方法是通过实例变量student.name=zrx或者self变量self.name=zrx
但 也有可能Student本身需要绑定 一个属性,可以直接在 class中定义属性 ,这是类属性 ,归student类所有 :

class Student(object):
    name = 'Student'

当定义 了类属性后,属性虽归类所有,但类的所有实例都可以访问到。

class Student(object):
    name = 'student'
s = Student()       #新建实例
print(s.name)       #输出类属性 
print(Student.name) #输出类属性
s.name = 'zrx'      #设置实例属性,且实例属性比类属性优先级高
print(s.name)       #输出实例属性 
print(Student.name) #但类属性没有消失,这样还是能输出
del s.name          #删除实例属性
print(s.name)       #找不到实例属性了,输出类属性

结果:
在这里插入图片描述

所以千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。

面向对象高级编程

一般情况下,定义了一个class又创建相应实例后,可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。
例:给实例 绑定属性

class Student(object):
    pass
s = Student()
s.name = 'Michael'
print(s.name)

例:给实例绑定方法 (只能这个实例使用该 方法)

def set_age(self, age):
    self.age  = age
from types import  MethodType
s.set_age = MethodType(set_age, s)  #给实例绑定一个方法
s.set_age(25)       #调用实例方法
print(s.age)        #测试结果

例:给class绑定 方法,所有实例都可以用该方法

def set_score(self, score):
    self.score = score
Student.set_score = set_score	#给类绑定方法

s.set_score(100)
print(s.score)

使用__slots__

但是随随便便就能给实例添加属性,打字打错了 添加上也看不出来,所以 还是要限制实例属性的。
在定义class的 时候,定义一个__slots__变量,来限制该class实例能添加的属性。

class Student(object):
    __slots__ = ('name', 'age') #用tuple定义允许绑定的属性名称

s  =  Student()
s.name = 'zrx'
s.age = 25
s.score = 99

报错:AttributeError: 'Student' object has no attribute 'score'

注意:__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的!!
在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__

使用@property

在绑定属性时,如果直接把属性暴露出去,写起来简单但是 没办法检查过滤不合理的参数。

class Student(object):
    def get_score(self):
        print(self._score)
    def set_score(self,value):
        if not isinstance(value, int):
            raise ValueError('score  mus be an integer!!!> _ <')
        if  value < 0 or  value >  100:
            raise  ValueError('score  must between 0~100! > _ <')
        self._score = value

s =  Student()
s.set_score(60)
s.get_score()
# s.set_score('999')  出错

但这样写教程嫌麻烦 ,希望写出又能检查参数,又能用属性这种方式简单访问 的变量 。
decorator装饰器可以给函数动态加上功能,对于类 ,装饰器一样起作用,python内置的@property装饰器就是负责把一个方法变成属性调用的。
将类方法转换为类属性,可以用’ . '直接获取属性值或者对属性进行赋值。
例:用property代替getter和setter

class Student(object):

    @property       #使用@property装饰price方法,这是get方法
    def score(self):
        return self._score

    @score.setter   #使用@property装饰方法,当对price赋值时,调用装饰方法
    def  score(self, value):
        if  not isinstance(value, int):
            raise ValueError('score must be  an integer!!')
        if value < 0  or  value > 100:
            raise ValueError('score must  between 0~100!!')
        self._score  = value

@preporty的实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上 @property就可以了 ,此时,@property本身又创建了另一个装饰器@score.setter,负责把 一个setter方法变成属性赋值,于是就拥有了可控的属性操作:

  • 调用被装饰的方法的时候是不用加括号的
  • 方法定义 的时候有 且只能有self 一个参数

property方法可以接收四个参数
第一个参数是获得属性的方法名,调用 对象.属性时自动触发
第二个参数是设置属性的方法名, 给属性赋值时自动触发
第三个参数是删除属性的方法名,删除属性时自动触发
第四个参数是字符串,是属性的描述文档,调用对象.属性.doc时触发

@property装饰器笔记参考 :https://zhuanlan.zhihu.com/p/121854031

多重继承

继承是面向对象的重要方式,通过继承子类可以扩展父类的功能
比如狗既继承了哺乳动物类,又继承了跑步类,通过多重继承,一个子类就可以同时获得多个父类的所有功能。

class Dog(Mammal, Runnable):
    pass

Maxln
在设计类的继承关系时,主线都是单一继承下来的,比如Ostrich继承 bird。但是,需要额外的功能时,就需要多重继承了,比如让Ostrich再继承Runnable,这种设计称为Mixln.

class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):
    pass

Mixln的目的就是给一个类增加多个功能,在设计类的时候,优先考虑通过多重继承
来 组合 多个 Mixln的功能 ,而不是射击多层次的复杂继承关系。
python自带的 很多库也使用了Mixln,例如TCPServer和UDPServer这两类网络服务,而要 同时服务多个 用户 就必须使用 多进程或多线程模型,这两种模型由ForkingMixIn和ThreaadingMixIn提供。通过组合,我们就可以 创造出 合适的服务来。
例:多进程模式的TCP服务

class MyTCPServer(TCPServer,  ForkingMixIn):
    pass 

例:编写一个多线程的UDP服务

class  MyUDPServer(UDPServer, ThreadingMixIn):
    pass

例:协成模型

class MyTCPServer(TCPServer,  CoroutineMixIn)
    pass

这样不用复杂庞大的继承链,只要 选择组合不同类的功能即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值