python之面向对象编程

一、__new__()

当使用"类名( [实参])"创建实例对象时,Python解释器的主要处理过程包括两大步:

  • 调用特殊方法__new__()创建实例对象

首先会查找该类对象是否实现了特殊方法__new__(), 如果没有实现,则去其父类中依次查找,直到类对象object。

  • 调用特殊方法__init__()对创建的实例对象进行初始化
    __new__ ( )返回的实例对象会作为实参被自动传递给__init__ ()的第一个形参self。
class Parent (object):
	def __new__ (cls, *args, **kwargs):
		pass
		
class Child(Parent):
	def __init__(self, name):
		pass

id (Parent)  #返回结果74270440

id(Child)  #返回结果74278936

二、__getitem__()、__setitem__()与__delitem__()

对于自定义类对象的实例对象,在默认情况下,是不能像列表和字典那样使用中括号语法来操作数据的。

如果想让自定义类对象的实例对象可以像列表和字典那样,使用中括号语法来操作数据,必须在自定义类对象中实现以下特殊方法:

  • __getitem__(self, key)
    当执行操作obj [key]时,会自动调用该特殊方法。
  • __ setitem__(self, key, value)
    当执行操作obj [key] = vaLue时,会自动调用该特殊方法。
  • __ delitem__(self, key)
    当执行操作del obj [key]时,会自动调用该特殊方法。
class MyDict(object):
	def __init__ (self):
		self. data = {}

	def __getitem__ (self, key):
		return self.data[key]
		
	def __setitem__(self, key, value) :
		self. data[key] = value
		
	def __delitem__(self, key):
		del self. data [key]

md = MyDict()
md["one"] = 18
md["two"] = 32
print (md.data)  #返回结果:{'one': 18, 'two' : 32}

del md[" two"]
print (md. data)   #返回结果:{'one': 18}

三、__call__()与callable()

如果在类对象中实现了特殊方法__call__ (), 那么就可以像调用函数一样直接调用这个类对象的实例对象,从而会自动调用特殊方法call_ ()。

class MyClass(object) :
	def __call__ (self, *args, **kwargs) :
		print (args, kwargs)
		
mc= MyClass()
mc()  #返回结果:() {}

mc(1,2,x=3,y=4)  #返回结果:(1, 2) {'x': 3,'y': 4]

内置函数callable用于判断指定对象是否是可调用的。
除了函数对象是可调用的之外,对于实现了特殊方法__call__ ()的类对象, 其实例对象也是可调用的。

>>>callable(print)    #内置函数是可调用的
True
>>>def my_fun(): #自定义函数也是 可调用的
>>>	pass
>>>print(callable(my_ fun))
True
>>>print(callable(MyClass())  #实现了特殊方法__call__( )的类对象,其实例对象也是可调用的。
True

四、__doc__与__dict__

调用内置函数dir得到的类对象的所有属性中,有一个特殊属性叫__doc__, 用于表示类对象的文档字符串。

  • 类对象的文档字符串
    与函数的文档字符串类似,位于类对象的第一行的字符串被称为类对象的文档字符串,通常用三个引号表示。
    类对象的文档字符串是对类对象的功能的简要描述。
  • 访问类对象的文档字符串
    通过类对象的特殊属性__doc__ 可以访问类对象的文档字符串。
    调用内置函数help()得到的帮助信息中会包含类对象的文档字符串。
class MyClass(object):
	"""这是类对象的文档字符串
	1
	2
	3
	"""
	pass

  print (MyClass.__doc__)
返回结果:
  这是类对象的文档字符串
	1
	2
	3

对于指定的类对象或实例对象,可以访问特殊属性__dict__ 获得该类对象或实例对象所绑定的所有属性和方法的字典。其中,字典中的键为属性名或方法名。

五、特殊属性之__slots__

Python是动态语言,所以,在创建对象之后,可以对其动态地绑定属性和方法。
如果想要对实例对象动态绑定的属性和方法的名称进行限制,可以在其对应的类对象中定义特殊属性__ slots__, 并给__slots__ 赋值一个所有元素都为字符串的列表或元组,这样,对实例对象动态绑定的属性和方法的名称就只能来自于__slots__ 中的元素。

class MyClass (object):
	__slots__ = ("attrl", "do_sthl")

mc = MyClass()  #返回结果:mc. attr1 = 18
print (mc. attr1)   #返回结果:18
mc. attr2 = 56    #返回结果:错误

def do_sth1(self):
	print("do_sth1被调用了")

from types import MethodType
mc. do_sth1 = MethodType(do_sth1, mc)

mc. do_ sth1()   #返回结果:do_sth1被调用了

def do_sth2(self):
	print("do_sth2被调用了")
	
mc. do_sth2 = MethodType(do_sth2, mc)  #返回结果:错误

默认情况下,访问实例对象的属性是通过访问该实例对象的特殊属性__dict__ 来实现的。例如:访问obj.x其实访问的是obj.dict [‘x’]

在类对象中定义了特殊属性__slots__后,其实例对象就不会在创建特殊属性__dict__ 了,而是为每个属性创建一个描述器,访问属性时就会直接调用这个描述器。调用描述器比访问__dict__ 要快,因此,在类对象中定义特殊属性__slots__ 可 以提高属性的访问速度。

此外,在类对象中定义了特殊属性__slots__ 后, 由于其实例对象不再创建特殊属性__dict__ , 同时,特殊属性__dict__ 是一个字典,字典的本质是哈希表,是一种用空间换取时间的数据结构,因此,在类对象中定义特殊属性__ slots__ 可以减少内存消耗。

  • 特殊属性__slots__只对其所在类对象的实例对象起作用,对其所在类对象的子类的実例实例对象是不起作用的。
  • 如果子类也定义了特殊属性__slots__,那么子类的实例对象可以动态绑定的属性和方法的名称为子类的__slots__ 加上父类的__ slots__。

六、特殊方法之__len__()

内置函数len( )用于返回对象的长度。
内置函数len()的实参在默认情况下不能是自定义类对象的实例对象。

print(len([1,2,3, 4, 5]))  #5
print(len('abcde' )) #5
print(len({'a' : 1, 'b’: 2,’c': 3}))  #3

class MyClass (object):
	pass

print(len(MyClass()))  #运行错误

如果想让内置函数len( )的实参可以是自定义类对象的实例对象,必须在自定义类对象中实现特殊方法__len__ (), 这样,调用内置函数Len()时,在其内部会自动调用实参所对应类对象的特殊方法__len__().之所以内置函数len()的实参可以是上述内置类对象的实例对象,是因为上述的内置类对象中都实现了特殊方法__len__()。

class MyClass (object) :
	def __len__(self):
		return 18

print(len(MyClass()))  #返回结果:18

七、生成器

查看生成器对应的所有元素,有两种方式:

  1. 多次调用内置函数next(),每次调用都返回生成器的下一个元素,直到抛出异常StopIteration时表示没有更多元素了。
  2. 使用for-in语句对生成器进行迭代,这样就不需要关心异常StopIteration了。

生成器函数 yield

  • 生成器中保存的并不是其对应的所有元素,而是如何推算出所有元素的算法。将生成器用于for-in语句时元素是在循环的过程中不断被推算出来的。将生成器作为内置函数next()的实参时,返回的下一个元素也是在调用函数时被推算出来的。因此,生成器是惰性推算的,也就是说,只有当用到生成器中的某个元素时,才会临时进行推算,而并不会提前推算出来。

  • 如果需要创建一个元素个数较大的容器,就可以考虑使用生成器,从而节省大量的存储空间。

  • 上面使用类似生成式的语法得到的生成器被称为生成器表达式。此外,当推算的算法比较复杂时,还可以使用生成器函数得到生成器。

  • 生成器函数中通过关键字yield返回推算出的元素。生成器函数与普通函数的区别在于:当调用内置函数next()或使用for-in语句进行迭代时,执行完yield语句就会将生成器函数挂起,下次会从挂起的地方继续执行。

八、迭代器

  • 可以用于for-in语句的对象被称为可迭代(Iterable)对象。
    例如: range、 列表、元组、字符串、字典、集合、生成器,都是可迭代对象。
  • 可以调用内置函数isinstance0判断一个对象是否是可迭代
    对象。标准库模块collections中的类Iterable用于表示可迭代对象。
from collections import Iterable
print(isinstance([1, 2, 3], Iterable))   #True
print (isinstance( abc' , Iterable))  #True
print (isinstance((i * i for i in range(1, 7)), Iterable))  #True
  1. 如果一个可迭代対象可以作カ内置函数next()的实参从而支持惰性推算,那么该対象被称为迭代器(Iterator) 对象。

  2. 对于range、列表、元组、字符串、字典和集合等可迭代対象,都不可以作カ内置函数next( )的实参,而生成器可以。所以,生成器是迭代器的一种。

  3. 可以调用内置函数isinstance()判断一个对象是否是迭代器对象。标准库模块collections中的类Iterator用于表示迭代器对象。

  4. 可以调用内置函数iter()把不支持惰性推算的可迭代对象转换为迭代器对象。

  5. 如果一个对象同时实现了特殊方法__iter__ ()和__next__ (), 那么该对象也被称为迭代器对象。如果将该对象用于for- in语句,for- in语句首先会调用特殊方法__iter__()返回一个可迭代对象,然后不断调用该可迭代对象的特殊方法__next__ ()返回下一 次迭代的值直到遇到StopIteration时退出循环。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值