Python 特殊方法

目录

 

7.1 如何派生内置不可变类型并修改实例化行为

7.2 如何为创建大量实例节省内存

7.3 如何让对象支持上下文管理器

7.4 如何创建可管理的对象属性


7.1 如何派生内置不可变类型并修改实例化行为

 1. __new__ 和 __init__

 object.__new__(cls[, ...])   

__new_()是在对象的实例化中被调用的第一个方法, 是一个静态方法,不需要显式地声明。它会将类作为第一个参数,其余参数传递给对象构造器表达式,返回值为新对象实例 。

示例:派生元祖类,定义一个元素仅为 int 类型的新元组。

#在 __new_()中对数据进行过滤

>>> class IntTuple(tuple):
	def __new__(cls,iterable):
		g = (i for i in iterable if isinstance(i,int))
		return super().__new__(cls,g)
	def __init__(self,iterable):
		super().__init__()


>>> l
[1, 2, 'gyf', 45]	
	
>>> a = IntTuple(l)
>>> a
(1, 2, 45)

7.2 如何为创建大量实例节省内存

8.4 创建大量对象时节省内存方法

给类添加 __slots__ 属性

演示对比:

>>> class Customer:
	def __init__(self,id,name,level):
		self.id = id
		self.name = name
		self.level = level


'''使用了 __slots__ 属性
'''		
>>> class New_customer:
	__slots__ = ['id','name','level']
	def __init__(self,id,name,level):
		self.id = id
		self.name = name
		self.level = level

两个类的示例差异:

>>> c = Customer(7,'gyf',100)
>>> c_n = New_customer(7,'gyf',100)

>>> set(dir(c)) - set(dir(c_n))
{'__weakref__', '__dict__'}

>>> import sys

>>> sys.getsizeof(c.__dict__)
112
>>> sys.getsizeof(c.__weakref__)
16

可见使用了 __slots__ ,示例少了两个属性'__dict__', '__weakref__' ,从而节省了内存。使用slots一个不好的地方就是我们不能再给实例添加新的属性了,只能使用在 __slots__ 中定义的那些属性名。

object.__dict__

一个字典或其他类型的映射对象,用于存储对象的(可写)属性。

__dict__是一个dict,它和数据对象的属性直接关联,可以直接通过__dict__访问、设置、修改、删除属性,比如类的对象实例可以通过 self.x=3 设置x属性,也可以通过 __dict__['x']=3 来设置属性x。而dir()函数仅仅只是展现一些属性。

7.3 如何让对象支持上下文管理器

给类添加 __enter__()  和  __exit__() 方法

8.3 让对象支持上下文管理协议

7.4 如何创建可管理的对象属性

直接访问对象的属性可能是不安全的,或者是设计上不灵活。比如 Customer类的 _level 属性只能是 1~4,直接访问属性就会没办法对此进行限制。

改进为调用方法的形式来访问属性:

>>> class Customer_new:
	def __init__(self,id,name):
		self.id = id
		self.name = name
		
	def getlevel(self):
		return self._level
	
	def setlevel(self,_level):
		if _level not in (1,2,3,4):
			raise ValueError('Level must be 1~4')
		self._level = _level
		
	def dellevel(self):
		del self._level

		
>>> gyf = Customer_new(7,'gyf')
>>> gyf.setlevel(3)
>>> gyf.getlevel()
3
>>> gyf.dellevel()
>>> gyf.getlevel()  #属性删除了
Traceback (most recent call last):
  File "<pyshell#127>", line 1, in <module>
    gyf.getlevel()
  File "<pyshell#119>", line 8, in getlevel
    return self._level
AttributeError: 'Customer_new' object has no attribute '_level'

调用方法的形式来访问属性虽然解决了直接访问的问题,但是会使访问变得不简洁。

改进:

class property(fget=Nonefset=Nonefdel=Nonedoc=None)

返回 property 属性。

fget 是获取属性值的函数。 fset 是用于设置属性值的函数。 fdel 是用于删除属性值的函数。并且 doc 为属性对象创建文档字符串。

>>> class Customer_new:
	def __init__(self,id,name):
		self.id = id
		self.name = name
		
	def getlevel(self):
		return self._level
	
	def setlevel(self,_level):
		if _level not in (1,2,3,4):
			raise ValueError('Level must be 1~4')
		self._level = _level
		
	def dellevel(self):
		del self._level

	level = property(getlevel,setlevel,dellevel)
    
	
>>> gyf = Customer_new(7,'gyf')
>>> 
>>> gyf.level = 3
>>> gyf.level
3
>>> del gyf.level
>>> gyf.level
Traceback (most recent call last):
  File "<pyshell#166>", line 1, in <module>
    gyf.level
  File "<pyshell#159>", line 7, in getlevel
    return self._level
AttributeError: 'Customer_new' object has no attribute '_level'
>>> 

或者使用 @property装饰器

>>> class Customer_new:
	def __init__(self,id,name):
		self.id = id
		self.name = name

	@property	
	def level(self):
		return self._level
	@level.setter
	def level(self,_level):
		if _level not in (1,2,3,4):
			raise ValueError('Level must be 1~4')
		self._level = _level
	@level.deleter	
	def level(self):
		del self._level

		
>>> gyf = Customer_new(7,'gyf')
>>> 
>>> gyf.level #还没level属性
Traceback (most recent call last):
  File "<pyshell#176>", line 1, in <module>
    gyf.level
  File "<pyshell#173>", line 8, in level
    return self._level
AttributeError: 'Customer_new' object has no attribute '_level'
>>> gyf.level = 3
>>> gyf.level
3
>>> del gyf.level

@property会将 level 方法转化为 level.getter方法,@level.setter 和 @level.deleter 则把 level 方法转化为 level.setter 和 level.deleter 方法

7.5 如何让类支持比较操作

__lt__ , __le__  , __gt__ , __ge__  ,__eq__ , __ne__

或者 functools 模块的 total.ordering 装饰器

7.6 如何使用描述符对实例属性做类型检查

__get__  , __set__  , __delete__

7.7 如何通过实例方法名字的字符串调用方法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值