python  算术运算

1、常用算术运算

__add__ (self, other)

定义加法的行为:+

__sub__ (self, other)

定义减法的行为: -

__mul__ (self, other)

定义乘法的行为: *

__truediv__ (self, other)

定义真除法的行为:/

__floordiv__ (self, other)

定义整数除法的行为: //

__mod__ (self, other)

定义取模算法的行为: %

__divmod__ (self, other)

定义当被divmod0调用时的行为

__pow__ (self, other[ modulo])

定义当被power(调用或**运算时的行为

__Ishift__ (self, other)

定义按位左移位的行为: <<

__rshift__ (self, other)

定义按位右移位的行为: >>

__and__ (self, other)

定义按位与操作的行为: &

__xor__ (self, other)

定义按位异或操作的行为: A

__or__(self, other)

定义按位或作的行为: |

 

自定义类中重写算术运算函数

也就是重载运算符,也实现自定义类型的算术运算操作

>>> class New_int(int):
	def __add__(self,other):
		return int.__sub__(self,other)
	def __sub__(self,other):
		return int.__add__(self,other)

	
>>> a = New_int(3)
>>> b = New_int(5)
>>> a+b
-2
>>> a-b
8

定义一个坐标相加的类,重载加号

>>> class point():
	def __init__(self,x,y):
		self.x = x
		self.y = y
	def __add__(self,other):
		out_x = self.x + other.x
		out_y = self.y + other.y
		return out_x,out_y
>>> class point3(point):
	def __init__(self,x,y,z):
		self.z = z
		super().__init__(x,y)
	def __add__(self,other):
		out_x = self.x + other.x
		out_y = self.y + other.y
		out_z = self.z + other.z
		return out_x,out_y,out_z

>>> p1 = point3(1,2,3)
>>> p2 = point3(4,5,6)
>>> p1 + p2
(5, 7, 9)

下面这样写会陷入无限递归

因为+调用add,add函数里又有+,死循环

class Error_int(int):
	def __add__(self,other):
		return self + other
	def __sub__(self,other):
		return self - other

解决方法是:可以先对类转化为整型

>>> class Correct_int(int):
	def __add__(self,other):
		return int(self) + int(other)
	def __sub__(self,other):
		return int(self) - int(other)

	
>>> a = Correct_int(3)
>>> b = Correct_int(5)
>>> a + b
8

python可以重写类

>>> class int(int):
	def __add__(self,other):
		return int.__sub__(self,other)

	
>>> a = int('5')
>>> a
5
>>> b = int(3)
>>> a + b
2

2、类的内置函数 魔方方法

_new__(cls[, ...])

1. __new__ 是在一个对象实例化的时候所调用的第一个方法

2. 它的第一个参数是这个类,其他的参数是用来直接传递给 __init__ 方法

3. __new__ 决定是否要使用该 __init__ 方法,因为 __new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __new__ 没有返回实例对象,则 __init__ 不会被调用

4. __new__ 主要是用于继承一个不可变的类型比如一个 tuple 或者 string

__init__(self[, ...])

构造器,当一个实例被创建的时候调用的初始化方法

__del__(self)

析构器,当一个实例被销毁的时候调用的方法

__call__(self[, args...])

允许一个类的实例像函数一样被调用:x(a, b) 调用 x.__call__(a, b)

__len__(self)

定义当被 len() 调用时的行为

__repr__(self)

定义当被 repr() 调用时的行为  __repr__() 方法是类的实例化对象用来做“自我介绍”的方法,默认情况下,它会返回当前对象的“类名+object at+内存地址”,而如果对该方法进行重写,可以为其制作自定义的自我描述信息。

__str__(self)

定义当被 str() 调用时的行为

__bytes__(self)

定义当被 bytes() 调用时的行为

__hash__(self)

定义当被 hash() 调用时的行为

__bool__(self)

定义当被 bool() 调用时的行为,应该返回 True 或 False

__format__(self, format_spec)

定义当被 format() 调用时的行为

 

有关属性

__getattr__(self, name)

定义当用户试图获取一个不存在的属性时的行为

__getattribute__(self, name)

定义当该类的属性被访问时的行为

__setattr__(self, name, value)

定义当一个属性被设置时的行为

__delattr__(self, name)

定义当一个属性被删除时的行为

__dir__(self)

定义当 dir() 被调用时的行为

__get__(self, instance, owner)

定义当描述符的值被取得时的行为

__set__(self, instance, value)

定义当描述符的值被改变时的行为

__delete__(self, instance)

定义当描述符的值被删除时的行为

 

比较操作符

__lt__(self, other)

定义小于号的行为:x < y 调用 x.__lt__(y)

__le__(self, other)

定义小于等于号的行为:x <= y 调用 x.__le__(y)

__eq__(self, other)

定义等于号的行为:x == y 调用 x.__eq__(y)

__ne__(self, other)

定义不等号的行为:x != y 调用 x.__ne__(y)

__gt__(self, other)

定义大于号的行为:x > y 调用 x.__gt__(y)

__ge__(self, other)

定义大于等于号的行为:x >= y 调用 x.__ge__(y)

 

算数运算符

__add__(self, other)

定义加法的行为:+

__sub__(self, other)

定义减法的行为:-

__mul__(self, other)

定义乘法的行为:*

__truediv__(self, other)

定义真除法的行为:/

__floordiv__(self, other)

定义整数除法的行为://

__mod__(self, other)

定义取模算法的行为:%

__divmod__(self, other)

定义当被 divmod() 调用时的行为

__pow__(self, other[, modulo])

定义当被 power() 调用或 ** 运算时的行为

__lshift__(self, other)

定义按位左移位的行为:<<

__rshift__(self, other)

定义按位右移位的行为:>>

__and__(self, other)

定义按位与操作的行为:&

__xor__(self, other)

定义按位异或操作的行为:^

__or__(self, other)

定义按位或操作的行为:|

 

反运算

__radd__(self, other)

(与上方相同,当左操作数不支持相应的操作时被调用)

__rsub__(self, other)

(与上方相同,当左操作数不支持相应的操作时被调用)

__rmul__(self, other)

(与上方相同,当左操作数不支持相应的操作时被调用)

__rtruediv__(self, other)

(与上方相同,当左操作数不支持相应的操作时被调用)

__rfloordiv__(self, other)

(与上方相同,当左操作数不支持相应的操作时被调用)

__rmod__(self, other)

(与上方相同,当左操作数不支持相应的操作时被调用)

__rdivmod__(self, other)

(与上方相同,当左操作数不支持相应的操作时被调用)

__rpow__(self, other)

(与上方相同,当左操作数不支持相应的操作时被调用)

__rlshift__(self, other)

(与上方相同,当左操作数不支持相应的操作时被调用)

__rrshift__(self, other)

(与上方相同,当左操作数不支持相应的操作时被调用)

__rand__(self, other)

(与上方相同,当左操作数不支持相应的操作时被调用)

__rxor__(self, other)

(与上方相同,当左操作数不支持相应的操作时被调用)

__ror__(self, other)

(与上方相同,当左操作数不支持相应的操作时被调用)

 

增量赋值运算

__iadd__(self, other)

定义赋值加法的行为:+=

__isub__(self, other)

定义赋值减法的行为:-=

__imul__(self, other)

定义赋值乘法的行为:*=

__itruediv__(self, other)

定义赋值真除法的行为:/=

__ifloordiv__(self, other)

定义赋值整数除法的行为://=

__imod__(self, other)

定义赋值取模算法的行为:%=

__ipow__(self, other[, modulo])

定义赋值幂运算的行为:**=

__ilshift__(self, other)

定义赋值按位左移位的行为:<<=

__irshift__(self, other)

定义赋值按位右移位的行为:>>=

__iand__(self, other)

定义赋值按位与操作的行为:&=

__ixor__(self, other)

定义赋值按位异或操作的行为:^=

__ior__(self, other)

定义赋值按位或操作的行为:|=

 

一元操作符

__pos__(self)

定义正号的行为:+x

__neg__(self)

定义负号的行为:-x

__abs__(self)

定义当被 abs() 调用时的行为

__invert__(self)

定义按位求反的行为:~x

 

类型转换

__complex__(self)

定义当被 complex() 调用时的行为(需要返回恰当的值)

__int__(self)

定义当被 int() 调用时的行为(需要返回恰当的值)

__float__(self)

定义当被 float() 调用时的行为(需要返回恰当的值)

__round__(self[, n])

定义当被 round() 调用时的行为(需要返回恰当的值)

__index__(self)

1. 当对象是被应用在切片表达式中时,实现整形强制转换

2. 如果你定义了一个可能在切片时用到的定制的数值型,你应该定义 __index__

3. 如果 __index__ 被定义,则 __int__ 也需要被定义,且返回相同的值

 

上下文管理(with 语句)

__enter__(self)

1. 定义当使用 with 语句时的初始化行为

2. __enter__ 的返回值被 with 语句的目标或者 as 后的名字绑定

__exit__(self, exc_type, exc_value, traceback)

1. 定义当一个代码块被执行或者终止后上下文管理器应该做什么

2. 一般被用来处理异常,清除工作或者做一些代码块执行完毕之后的日常工作

 

容器类型

__len__(self)

定义当被 len() 调用时的行为(返回容器中元素的个数)

__getitem__(self, key)

定义获取容器中指定元素的行为,相当于 self[key]

__setitem__(self, key, value)

定义设置容器中指定元素的行为,相当于 self[key] = value

__delitem__(self, key)

定义删除容器中指定元素的行为,相当于 del self[key]

__iter__(self)

定义当迭代容器中的元素的行为

__reversed__(self)

定义当被 reversed() 调用时的行为

__contains__(self, item)

定义当使用成员测试运算符(in 或 not in)时的行为

3、使用样例

 

__repr__(self)

定义当被 repr() 调用时的行为 repr()将对象变为字符串

__str__(self)

定义当被 str() 调用时的行为

1)__str__(self)的作用是: python使用print()打印实例化对象时调用__str__(),如果__str__()函数有返回值,打印这个函数的返回值。如果没写__str__()函数,print打印的是地址

>>> class A():
	def __init__(self,x):
		self.x = x
	def __str__(self):
		return str(self.x)  #print打印 self.x

	
>>> a = A(1)
>>> a
<__main__.A object at 0x7fdc3b04c390>
>>> print(a)
1


>>> class B():                 #没有__str__() print打印地址
	def __init__(self,x):
		self.x = x
		
>>> b = B(1)
>>> b
<__main__.B object at 0x7fdc36186470>
>>> print(b)
<__main__.B object at 0x7fdc36186470>
>>> class A():                        #print打印__str__()的返回值
...     def __str__(self):
...             return "调用了str()..."
... 
>>> a = A()
>>> print(a)
调用了str()...
>>> a
<__main__.A object at 0x7fb74a97e3c8>
>>> class A(str):                       #print打印__str__()的返回值
...     def __str__(self):
...             return "继承了str..."
... 
>>> b = A("abc")
>>> b
'abc'
>>> print(b)
继承了str...

2)__repr__() 类似于__str__() ,重写__repr__ 可以输入对象打印对象的属性值.python中 object 类提供的 __repr__() 方法总是返回该对象实现类的“类名+object at+内存地址”值,如果用要返回属性指或是别的,重写 __repr__() 方法。

与__str__()不同的是 直接键入实例化对象也会打印出repr的返回值,而不用print也可以

如果对象内只有__repr__,调用str() ,str()也会调用__repr__()

>>> class B():
...     def __repr__(self):
...             return "调用了repr..."
... 
>>> b = B()
>>> b
调用了repr...
>>> class A():
	def __repr__(self):
		return "调用repr..."

	
>>> a = A()
>>> a          #不用print也能打印
调用repr...
>>> print(a)
调用repr...
>>> print(repr(a))  #可以直接使用repr调用
调用repr...
>>> print(str(a))
调用repr...
>>> str(a)     #没有__str__ str调用了__repr__
'调用repr...'
>>> class A():
	def __repr__(self):
		return "调用repr..."
	def __str__(self):
		return "调用str..."

	
>>> a = A()
>>> a
调用repr...
>>> print(a)
调用str...
>>> print(str(a))
调用str...
>>> print(repr(a))
调用repr...
>>> str(a)
'调用str...'

注意 __str__()和__repr__()影响打印的值,不影响str()和repr()的使用,str()出来的值是给人看的字符串,repr()出来的值是给机器看的,括号中的任何内容出来后都是在它之上再加上一层引号。

>>> a = "hello"
>>> str(a)
'hello'
>>> repr(a)
"'hello'"

3) __new__()  类似构造函数,一般不要改写

http://c.biancheng.net/view/5484.html

  __new__() 通常会返回该类的一个实例,但有时也可能会返回其他类的实例,如果发生了这种情况,则会跳过对 __init__() 方法的调用。而在某些情况下(比如需要修改不可变类实例(Python 的某些内置类型)的创建行为),利用这一点会事半功倍。

class nonZero(int):
    def __new__(cls,value):
        return super().__new__(cls,value) if value != 0 else None
    def __init__(self,skipped_value):
        #此例中会跳过此方法
        print("__init__()")
        super().__init__()
print(type(nonZero(-12)))
print(type(nonZero(0)))


#输出结果
__init__()
<class '__main__.nonZero'>
<class 'NoneType'>

4)__del__()

来自:http://c.biancheng.net/view/2371.html

__init__() 方法用于初始化 Python 对象,而 __del__() 则用于销毁 Python 对象,即在任何 Python 对象将要被系统回收之时,系统都会自动调用该对象的 __del__() 方法。当程序不再需要一个 Python 对象时,系统必须把该对象所占用的内存空间释放出来,这个过程被称为垃圾回收(GC,Garbage Collector),Python 会自动回收所有对象所占用的内存空间,因此开发者无须关心对象垃圾回收的过程。

Python 采用自动引用计数(ARC)方式来回收对象所占用的空间,当程序中有一个变量引用该 Python 对象时,Python 会自动保证该对象引用计数为 1;当程序中有两个变量引用该 Python 对象时,Python 会自动保证该对象引用计数为 2,依此类推,如果一个对象的引用计数变成了 0,则说明程序中不再有变量引用该对象,表明程序不再需要该对象,因此 Python 就会回收该对象。

 大部分时候,Python 的 ARC 都能准确、高效地回收系统中的每个对象。但如果系统中出现循环引用的情况,比如对象 a 持有一个实例变量引用对象 b,而对象 b 又持有一个实例变量引用对象 a,此时两个对象的引用计数都是 1,而实际上程序已经不再有变量引用它们,系统应该回收它们,此时 Python 的垃圾回收器就可能没那么快,要等专门的循环垃圾回收器(Cyclic Garbage Collector)来检测并回收这种引用循环。

当一个对象被垃圾回收时,Python 就会自动调用该对象的 __del__ 方法。需要说明的是,不要以为对一个变量执行 del 操作,该变量所引用的对象就会被回收,只有当对象的引用计数变成 0 时,该对象才会被回收。因此,如果一个对象有多个变量引用它,那么 del 其中一个变量是不会回收该对象的。

最后需要说明的是,如果父类提供了 __del__() 方法,则系统重写 __del__() 方法时必须显式调用父类的 __del__() 方法,这样才能保证合理地回收父类实例的部分属性。

class Item:
    def __init__ (self, name, price):
        self.name = name
        self.price = price
    # 定义析构函数
    def __del__ (self):
        print('del删除对象')
# 创建一个Item对象,将之赋给im变量
im = Item('鼠标', 29.8)
x = im   # ①
# 打印im所引用的Item对象
del im
print('--------------')

程序中重写了 Item 类的 __del__() 方法,该方法就是 Item 类的析构函数,当系统将要回收 Item 时,系统会自动调用 Item 对象的 __del__() 方法。

上面程序先创建了一个 Item 对象,并将该对象赋值给 im 变量,① 号代码又将 im 赋值给变量 x,这样程序中有两个变量引用 Item 对象,接下来程序执行 del im 代码删除 im 对象,此时由于还有变量引用该 Item 对象,因此程序并不会回收 Item 对象。

运行上面程序,可以看到如下输出结果:

--------------
del删除对象

从上面程序的输出结果可以看到,del im 执行之后,程序并没有回收 Item 对象,只有等到程序执行将要结束时(系统必须回收所有对象),系统才会回收 Item 对象。

如果将程序中 ① 号代码注释掉,再次运行上面程序,将会看到如下输出结果:

del删除对象
--------------

注释掉 ① 号代码之后,当程序执行 del im 之后,此时程序中不再有任何变量引用该 Item 对象,因此系统会立即回收该对象,则无须等到程序结束之前。

5) __dir__ 对象的 __dir__ 方法用于列出该对象内部的所有属性(包括方法)名,该方法将会返回包含所有属性(方法)名的序列。

class Item:
    def __init__ (self, name, price):
        self.name = name
        self.price = price
    def info ():
        pass
# 创建一个Item对象,将之赋给im变量
im = Item('显卡', 14999)
print(im.__dir__())  # 返回所有属性(包括方法)组成列表
print(dir(im))  # 返回所有属性(包括方法)排序之后的列表

(http://c.biancheng.net/view/2372.html)
当程序对某个对象执行 dir(object) 函数时,实际上就是将该对象的 __dir__() 方法返回值进行排序,然后包装成列表。

6)__dict__  属性用于查看对象内部存储的所有属性名和属性值组成的字典,通常程序直接使用该属性即可。

程序使用 __dict__ 属性既可查看对象的所有内部状态,也可通过字典语法来访问或修改指定属性的值。

class Item:
    def __init__ (self, name, price):
        self.name = name
        self.price = price
im = Item('鼠标', 28.9)
print(im.__dict__)  # ①
# 通过__dict__访问name属性
print(im.__dict__['name'])
# 通过__dict__访问price属性
print(im.__dict__['price'])
im.__dict__['name'] = '键盘'
im.__dict__['price'] = 32.8
print(im.name) # 键盘
print(im.price) # 32.8

{'name': '鼠标', 'price': 28.9}
鼠标
28.9
键盘
32.8

7)__call__()

(http://c.biancheng.net/view/2374.html)

>>> class Person:
	def __init__(self,name,age):
		self.name = name
		self.age = age
	def printinfo(self):
		print("%s的年龄是%d" % (self.name,self.age))

		
>>> p1 = Person("鸣人",16)
>>> print(hasattr(p1.name,'__call__'))
False
>>> print(hasattr(p1.age,'__call__'))
False
>>> print(hasattr(p1.printinfo,'__call__'))  #printinfo是方法 返回True
True

 python中在调用函数fun(param1,param2,...),实际形式是fun.__call__(param1,param2,...),所以也可以显示使用fun.__call__()的形式

可以自定义类添加 __call__ 方法,使得该类的实例也变成可调用的

>>> class SS:
	def __init__(self,name):
		self.name = name
	def __call__(self):
		print("叛变的%s" % self.name)

		
>>> s = SS('佐助')
>>> s()
叛变的佐助

 样例:

-定制一个计时器的类

- start和stop方法代表启动计时和停止计时

-假设计时器对象t1, print(t1)和直接调用t1均显示结果

-当计时器未启动或已经停止计时,调用stop方法会给予温馨的提示

-两个计时器对象可以进行相加:t1+t2

-只能使用提供的有限资源完成

使用time模块的localtime方法获取时间

-扩展阅读: time 模块详解(时间获取和转换)

time.localtime返回struct_ time的时间格式

表现你的类: __str__ 和 __repr__

import time as t 

class MyTimer():
    def __init__(self):
        self.unit = ['年','月','天','小时','分钟','秒']
        self.prompt = "未开始计时"
        self.lasted = []
        self.begin = 0
        self.end = 0

    def __str__(self):
        return self.prompt

    __repr__ == __str__

    def __add__(self,other):
        prompt = "总共运行了"
        result = []
        for index in range(6):
            result.append(self.lasted[index] + other.lasted[index])
            if result[index]:
                prompt += (str(result[index]) + self.unit[index])
        return prompt

    #开始计时
    def start(self):
        self.begin = t.localtime()
        self.prompt = "提示:请先调用stop() 停止计时!"
        print("开始计时")

    #停止计时
    def stop(self):
        if not self.begin:
            print("提示:请先调用start() 进行计时!")
        else:
            self.end = t.localtime()
            self._calc()
            print("计时结束")

    #内部方法计算运行时间
    def _calc(self):
        self.lasted = []
        self.prompt = "总共运行了"
        for index in range(6):
            self.lasted.apppend(self.end[index] - self.begin[index])
            if self.lasted[index]:
                self.prompt += (str(self.lasted[index])+self.unit[index])
        #为下一轮计时初始化变量
        self.begin = 0
        self.end = 0

4、类 重写属性访问

首先属性访问  hasattr,getattr,setattr

1)hasattr(object, name):查看对象object是否有名为那么的属性或方法,有返回True,没有返回False

2)getattr(object, name[,defalut]):可以得到对象object中属性名为name的属性值,可以设置参数default,当属性不存在的时候返回defalut

3)setattr(object,name,value):

>>> class point:
	def __init__(self,message,x,y):
		self.message = message
		self.x = x
		self.y = y
	def printtip(self):
		print("%s的位置是(%d, %d)" % (self.message,self.x,self.y))

		
>>> p1 = point("商场",20,100)
>>> print(hasattr(p1,'message'))  #判断是否包含属性‘message’
True
>>> print(hasattr(p1,'printinfo')) #判断是否包含属性‘printinfo’
False
>>> print(hasattr(p1,'printtip'))  #判断是否包含属性‘printtip’
True
>>> print(hasattr(p1,'x'))
True
>>> print(getattr(p1,'x'))   #获得属性'x'的值
20
>>> print(getattr(p1,'y'))   #获得属性'y'的值
100
>>> getattr(p1,'z',"不存在的属性")   #设置属性不存在时的返回值
'不存在的属性'
>>> print(getatt(p1,'printtip'))   #不能获取方法属性,报错未定义
Traceback (most recent call last):
  File "<pyshell#663>", line 1, in <module>
    print(getatt(p1,'printtip'))
NameError: name 'getatt' is not defined
>>> setattr(p1,'message','书店')    #重写设定属性值
>>> setattr(p1,'x',30)
>>> setattr(p1,'y',200)
>>> print(p1.x)
30
>>> print(p1.y)
200

另外,setattr可以为对象添加属性值,也就是在设置对象属性值得时候,对象的这个属性不存在,setattr会为对象添加一个属性。

#为上面的坐标加一个z,说明书店在地下一层
>>> setattr(p1,'z',-1)
>>> print(p1.z)
-10

setattr还可以重新设置方法 ,setattr() 函数重新设置对象的方法时, 新设置的方法是未绑定方法,是重写不是添加

>>>p1 = point("书店",30,200)
>>> setattr(p1,'printtip',info)
>>> p1.printtip()
书店今日不营业

setattr函数如果设置一个和方法同名的属性,方法会被掩盖不能使用

>>> setattr(p1,'printtip','欢迎光临')
>>> p1.printtip()
Traceback (most recent call last):
  File "<pyshell#687>", line 1, in <module>
    p1.printtip()
TypeError: 'str' object is not callable
>>> p1.printtip
'欢迎光临'

类内重写属性访问

__getattr__(self,name) 

__getattribute_ _(self, name )

__setattr__ (self, name, value) 

__delattr__ (self, name)

访问属性 上面函数的调用属性

>>> class C:
	def __getattribute__(self,name):
		print("getattribute")
		return super().__getattribute__(name)				
	def __getattr__(self,name):
		print("getattr")
	def __setattr__(self,name,value):
		print("setattr")
		super().__setattr__(name,value)
	def __delattr__(self, name):
		print("delattr")
		super().__delattr__(name)

		
>>> c =C()
>>> c.x            #看到getattr是先调用getattribute的
getattribute
getattr
>>> c.x = 1
setattr
>>> c.x
getattribute
1
>>> del c.x
delattr

类比下property

>>> class C:
	def __init__(self,size=10):
		self.size = size
	def getSize(self):
		return self.size
	def setSize(self,value):
		self.size = value
	def delSize(self):
		del self.size
	x = property(getSize, setSize,delSize)

	
>>> c = C()
>>> c.x = 1
>>> c.x
1
>>> c.size
1
>>> del c.x
>>> c.size
Traceback (most recent call last):
  File "<pyshell#736>", line 1, in <module>
    c.size
AttributeError: 'C' object has no attribute 'size'

写一个用例:

下面这个会陷入死循环 setattr引起的死循环

class Rectangle:
	def __init__(self,width=0,height=0):
		self.width = width
		self.height = height
	def __setattr__(self,name,value):
		if name == 'square':
			self.width = value
			self.height = value
		else:
			self.name = value   #这里会死循环

	def getArea(self):
		return self.width * self.height

 上面这段程序中的self.name = value 会调用__setattr__函数,__setattr__里面又有=操作,一直循环下去

改成 用基类的__setattr__()操作

class Rectangle:
	def __init__(self,width=0,height=0):
		self.width = width
		self.height = height
	def __setattr__(self,name,value):
		if name == 'square':
			self.width = value
			self.height = value
		else:
			super().__setattr__(name,value)

	def getArea(self):
		return self.width * self.height
>>> r = Rectangle(4,5)
>>> r.getArea()
20
>>> r.square = 10
>>> r.width
10
>>> r.height
10
>>> r.getArea()
100
>>> r.__dict__
{'width': 10, 'height': 10}

或者程序可以写成

>>> class Rectangle:
	def __init__(self,width=0,height=0):
		self.width = width
		self.height = height
	def __setattr__(self,name,value):
		if name == 'square':
			self.width = value
			self.height = value
		else:
			self.__dict__[name] = value

	def getArea(self):
		return self.width * self.height

 

3、描述符 类 property

描述符就是将某种特殊类型的类的实例指派给另一个类的属性

注意这里是给另一个类,下面的方法和上面的属性访问区别开来

本质上看,描述符就是一个类,只不过它定义了另一个类中属性的访问方式。换句话说,一个类可以将属性管理全权委托给描述符类。

描述符基于以下三个方法

__get__(self,instance,owner)

__set__(self,instance,value) 将在属性分配操作中调用,不返回任何内容  在设置属性时将调用这一方法

__delete__(self,instance)   控制删除操作,不返回任何内容   对属性调用 del 时将调用这一方法。

>>> class MyDecriptor:
	  def __get__(self,instance,owner):
		  print("调用__get__...",self,instance,owner)
	  def __set__(self,instance,value):
		  print("调用__set__...",self,instance,value)
	  def __delete__(self,instance):
		  print("调用__delete__...",self,instance)

		
>>> class Test:
	x = MyDecriptor()
	
>>> test = Test()
>>> test.x
调用__get__... 
<__main__.MyDecriptor object at 0x0000011E7FA80CF8> 
<__main__.Test object at 0x0000011E7FA80A58> <class '__main__.Test'>
>>> test
<__main__.Test object at 0x0000011E7FA80A58>
>>> Test
<class '__main__.Test'>
>>> test.x = 1
调用__set__... 
<__main__.MyDecriptor object at 0x0000011E7FA80CF8> <__main__.Test object at 0x0000011E7FA80A58> 1
>>> del test.x
调用__delete__...
 <__main__.MyDecriptor object at 0x0000011E7FA80CF8> <__main__.Test object at 0x0000011E7FA80A58>
#描述符类 http://c.biancheng.net/view/5468.html
class revealAccess:
    def __init__(self, initval = None, name = 'var'):
        self.val = initval
        self.name = name
    def __get__(self, obj, objtype):
        print("Retrieving",self.name)
        return self.val
    def __set__(self, obj, val):
        print("updating",self.name)
        self.val = val
class myClass:
    x = revealAccess(10,'var "x"')
    y = 5
m = myClass()
print(m.x)
m.x = 20
print(m.x)
print(m.y)

Retrieving var "x"
10
updating var "x"
Retrieving var "x"
20
5

定义自己的property

>>> class MyProperty:
	def __init__(self,fget=None, fset=None,fdel=None):
		self.fget = fget
		self.fset = fset
		self.fdel = fdel
	def __get__(self,instance,owner):
		return self.fget(instance)
	def __set__(self,instance,value):
		self.fset(instance,value)
	def __delete__(self,instance):
		self.fdel(instance)

		
>>> class C:
	def __init__(self):
		self._x = None
	def getX(self):
		return self._x
	def setX(self,value):
		self._x = value
	def delX(self):
		del self._x
	x = MyProperty(getX,setX,delX)

 

>>> c = C()
>>> c.x = 10
>>> c.x
10
>>> c._x
10
>>> del c.x

样例:

定义两个描述符,实现摄氏度和华氏度的自动转换

class Celsius:
	def __init__(self,value=26.0):
		self.value = float(value)
	def __get__(self,instance,value):
		return self.value
	def __set__(self,instance,value):
		self.value = float(value)

		
 class Fahreheit:
	def __get__(self,instance,owner):
		return instance.cel*1.8 + 32
	def __set__(self,instance,value):
		instance.cel = (float(value) - 32) / 1.8

		
 class Temperature:
	cel = Celsius()
	fah = Fahrenheit()

>>> t = Temperature()
>>> t.cel = 30
>>> t.fah
86.0