python学习笔记_11(魔法方法_属性_特性)

魔法方法,属性和迭代器


1. 魔法方法
  • 所有以双下划线开头和结尾的方法称为魔法方法

  • 构造方法,__init__ ,在对象创建是自动调用

    >>> class fooBar(object):
    	def __init__(self,):
    		self.somevar = 42
    
    		
    >>> f = fooBar()
    >>> f.somevar
    42
  • 重写一般方法和构造方法,通过继承子类调用方法没有找到时就会在超类中找,继承可以增加新的方法,也可以重写超类的方法

    >>> class A:
    	def hello(self):
    		print "Hello, I'm A"
    
    >>> class B(A):
    	pass
    >>> a = A()
    >>> b = B()
    >>> a.hello()
    Hello, I'm A
    >>> b.hello()
    Hello, I'm A
    
    #重写class B
    >>> class B(A):
    	def hello(self):
    		print "Hello, I'm B"
    
    		
    >>> b = B()
    >>> b.hello()
    Hello, I'm B
    #如果构造方法被重新了,就需要调用超类的方法,子类不仅要初始化自己,还需要初始化超类代码
    >>> class Bird(object):
    	def __init__(self):
    		self.hungry = True
    	def eat(self):
    		if self.hungry:
    			print 'Aaaah...'
    			self.hungry = False
    		else:
    			print 'No, thanks!'
    
    			
    >>> b = Bird()
    >>> b.eat()
    Aaaah...
    >>> b.eat()
    No, thanks!
    
    #添加子类SongBird,添加唱歌行为
    >>> class SongBird(Bird):
    	def __init__(self):
    		self.sound = 'Squawk!'
    	def sing(self):
    		print self.sound
            
    >>> sb = SongBird()
    >>> sb.sing()
    Squawk!
    >>> sb.eat()
    
    Traceback (most recent call last):
      File "<pyshell#55>", line 1, in <module>
        sb.eat()
      File "<pyshell#41>", line 5, in eat
        if self.hungry:
    AttributeError: SongBird instance has no attribute 'hungry'
    #由于SongBird重新了Bird的构造方法,但是构造方法中没有任何关于初始化hungry特性的代码
    #调用超类的构造方法有两种技术:调用超类构造方法的未绑定版本,或者使用super函数
    >>> class SongBird(Bird):
    	def __init__(self):
    		Bird.__init__(self)
    		self.sound = 'Squawk!'
    	def sing(self):
    		print self.sound
    #当前类和对象作为super函数的参数,调用函数返回对象的任何方法都是调用超类方法,super只在新式类中起作用
    >>> class SongBird(Bird):
    	def __init__(self):
            super(SongBird, self).__init__()
    		Bird.__init__(self)
    		self.sound = 'Squawk!'
    	def sing(self):
    		print self.sound
  • 其他魔法方法,只要遵守序列或映射的规则,可以实现类似序列或映射的行为,实现序列或映射的魔法方法

    • 基本序列和映射规则

      魔法方法说明
      __len__(self)这个方法应该返回集合中的所含项目的数量,序列返回元素个数,映射返回键值对的数量,如果返回0并且为重新__nonzero__,当作布尔值False,调用len()函数返回此方法值
      __getitem__(self,key)这个方法返回所给键对应的值,对于序列键为0~n-1,映射可以使用任何种类的键,通过[]运算访问是使用此方法
      __setitem__(self, key, value)设置给定的键对应的值,只能为可修改对象定义此方法
      __delitem__(self, key)调用del语句是调用,只能为可修改对象定义此方法
      对序列来说如果键是负整数,那么从末尾计数,
      如果键是不合适的类型,引发TypeError
      如果索引正确,但超出范围引发IndexError
    #创建无穷序列
    >>> def checkIndex(key):
    	if not isinstance(key, (int, long)):
    		raise TypeError
    	if key < 0:
    		raise IndexError
    
    >>> class ArithmeticSequence(object):
    	def __init__(self, start = 0, step = 1):
    		self.start = start
    		self.step = step
    		self.changed = {}
    	def __getitem__(self, key):
    		checkIndex(key)
    		try:
    			return self.changed[key]
    		except KeyError:
    			return self.start + key * self.step
    	def __setitem__(self, key, value):
    		checkIndex(key)
    		self.changed[key] = value
            
    >>> s = ArithmeticSequence(1, 2)
    >>> s[4]
    9
    >>> s[4] = 2
    >>> s[4]
    2
    >>> s[5]
    11
    >>> del s[4]
    
    Traceback (most recent call last):
      File "<pyshell#95>", line 1, in <module>
        del s[4]
    AttributeError: __delitem__
    #没有__len__方法,不能用len函数,引发TypeError
    >>> len(s)
    
    Traceback (most recent call last):
      File "<pyshell#96>", line 1, in <module>
        len(s)
    TypeError: object of type 'AtithmeticSequence' has no len()
    #索引类型正确,但超出范围
    >>> s[-1]
    
    Traceback (most recent call last):
      File "<pyshell#97>", line 1, in <module>
        s[-1]
      File "<pyshell#86>", line 7, in __getitem__
        checkIndex(key)
      File "<pyshell#90>", line 5, in checkIndex
        raise IndexError
    IndexError
    #索引类型不正确
    >>> s['a']
    
    Traceback (most recent call last):
      File "<pyshell#98>", line 1, in <module>
        s['a']
      File "<pyshell#86>", line 7, in __getitem__
        checkIndex(key)
      File "<pyshell#90>", line 3, in checkIndex
        raise TypeError
    TypeError
  • 子类化内建的类型,可以很容易创建相似的类型

    如以下通过继承list实现一个带计数功能的CountList

    >>> class CountList(list):
    	def __init__(self, *args):
    		super(CountList, self).__init__(*args)
    		self.count = 0
    	def __getitem__(self, index):
    		self.count += 1
    		return super(CountList, self).__getitem__(index)
    		
    >>> cl = CountList(range(10))
    >>> cl
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> cl.reverse()
    >>> cl
    [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
    >>> del cl[3:6]
    >>> cl
    [9, 8, 7, 3, 2, 1, 0]
    >>> cl.count
    0
    >>> cl[4] + cl[2]
    2
    
    2. 属性
    • 示例, getSize,setSize为名为Size特性的访问器方法
    >>> class Rectangle():
    	def __init__(self):
    		self.width = 0
    		self.height = 0
    	def setSize(self, size):
    		self.width, self.height = size
    	def getSize(self):
    		return self.width, self.height
    
    	
    >>> r = Rectangle()
    >>> r.width = 10
    >>> r.height = 5
    >>> r.getSize()

    新式类中更优雅实现,使用property

    >>> class Rectangle(object):
    	def __init__(self):
    		self.width = 0
    		self.height = 0
    	def setSize(self, size):
    		self.width, self.height = size
    	def getSize(self):
    		return self.width, self.height
    	size = property(getSize, setSize)
    
    	
    >>> r = Rectangle()
    >>> r.width = 10
    >>> r.height = 5
    >>> r.size
    (10, 5)
    >>> r.size = (100, 50)
    >>> r.width
    100
    #size特性还是由getSize和setSize中计算,但是看起来和普通属性一样的
    • property函数可以使用0,1,3,4个参数,如果没有参数,产生的属性既不可读也不可写,如果只使用一个参数,产生的的属性是只读的,第三个参数(可选)是用于删除特性的方法,第四个为文档字符串,四个参数分别叫fget,fset,fdel,doc,如果只读和文档字符串,可以使用关键字参数的方式来实现
3. 静态方法和成员方法
  • 静态方法,装入到staticmethod类型的对象中,静态方法的定义没有self,且能够被本身直接调用,静态方法不能访问类的特性和方法
  • 类成员方法,装入classmethod类型的对象中,定义时需要名为cls的类似self的参数,类成员方法可以直接用类的具体对象调用,但cls参数自动绑定到类
>>> class MyClass(object):
	var = 2
	@staticmethod
	def smeth():
		print var
		print 'This is a static method'
	@classmethod
	def cmeth(cls):
        print cls.var
		print 'This is a class method', cls
        
>>> MyClass.cmeth()
This is a class method <class '__main__.MyClass'>
>>> MyClass.smeth()

Traceback (most recent call last):
  File "<pyshell#178>", line 1, in <module>
    MyClass.smeth()
  File "<pyshell#175>", line 5, in smeth
    print var
NameError: global name 'var' is not defined
>>> 
4. __getattr__,__setattr__和他的朋友们
  • 拦截(intercept)对象所有特性(attribute)的访问是可能的,为了在访问特性时可以执行代码,必须使用一些魔法方法。

    魔法方法说明
    __getattribute__(self, name)当特性name被访问时被自动调用
    __getattr__(self, name)当特性name被访问且不存在时被自动调用,先调getattribute,getattribute判断特性不存在,再调用此方法
    __setattr__(self, name, value)当试图给特性赋值时被自动调用,默认是可以直接给特性赋值增加特性
    __delattr__(self, name)当试图删除特性时被自动调用
    getattr(obj, name)函数本质调用对象对应的魔法方法
    setattr(obj, name, value)函数本质调用对象对应的魔法方法
    delattr(obj, name)函数本质调用对象对应的魔法方法
    hasattr(obj, name)函数本质调用getattr魔法属性判断是否存在特性
    callable(obj)函数python 2中函数判断是否可调用,python 3中使用hasattr(obj, ‘__call__’)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值