1 Python中的类型与对象

来源:互联网 发布:第三方网络销售平台 编辑:程序博客网 时间:2024/06/05 07:17

类型与对象

转载请标明出处(http://blog.csdn.net/lis_12/article/details/52693637)

1 术语

程序中所有数据都是对象(实例),每个对象都有一个身份,一个类型和一个值.如a = 10,使用值10创建一个整数对象,对象的身份可以看做它在内存中所处位置的指针(id(a)获取),a就是引用这个位置的名称.

实例的类型决定了实例内部的表示以及它支持的方法.

实例被创建后,它的身份和类型就不可改变,如果对象的值是可以修改的称为可变对象(list,dict);如果对象的值不可修改称为不可变对象(int,str,tuple).

2 身份与类型

a = 10,b = 10

  1. 身份的获取,id(a);

  2. 类型的获取,type(a)

  3. is用来比较地址是否相同,即两个对象身份是否相同,==用来比较两个对象的值是否相同;

  4. type(a) is type(b) # true

    对象的类型本身也是一个对象,称为对象的类,该对象的定义是唯一的,对于某个类型的所有实例都是相同的.

  5. 检查某个实例的类型最佳方式是用,isinstance(object,(int,str,list…..))

3 引用计数与垃圾收集

所有对象都有引用计数,无论是给一个对象分配一个新名称,还是放入容器当中,都会让该对象的引用计数增加.

a = 10      #创建一个值为10的对象b = a       #增加10的引用计数c = []     c.append[a] #增加10的引用计数#上面只有一个包含10的对象,其他操作都只是创建了该对象的引用.del a       #减少10的引用计数,此时a也就无法访问了b = 10      #减少10的引用计数c[0] = 5    #减少10的引用计数'''使用del或者重新赋值时,对象的引用计数会减少'''print sys.getrefcount(b) #查看b的引用次数,一般情况下会比预想情况多- -a = {}b = {}a['a'] = bb['b'] = adel adel b'''虽然del语句销毁了a与b,但是他们相互引用,所以引用计数不会归零,对象也不会销毁(从而导致内存泄漏),为了解决这个问题,解释器会有一个循环检测器,搜索不可访问对象并删除.'''

4 引用和复制

a = 1b = 1print id(a)       #0print id(b)       #0#a与b的地址相同,因为1是不可变对象,不可改变,a和b都是对1的引用.a = range(10)b = range(10)print id(a)       #0print id(b)       #1#a与b的地址不同,因为list是可变对象,可变对象是可修改的for i,j in zip(a,b):    print id(i) == id(j)#result:10个True,因为list里面的对象都是不可变对象,a和b里面的元素分别引用了0,1,...,8,9
#可变对象a = range(4)b = ab[1] = 100print a    #[0,100,2,4]#不可变对象c = 1d = cd = 2print c    #1

a,b引用的是同一个对象,修改其中任何一个都会影响另一个,为了避免这种情况,必须创建对象的副本而不是新的引用.

可变对象的复制分为浅,深复制.

  • 浅复制将创建一个新对象,但它包含的是对原始对象中包含的项的引用.
a = [0,[1,2]]b = a      #此时b就相当于a的别名c = list(a)#创建a的一个浅复制a is b     #Truea is c     #Falseb.append(2)c.append(3)print a    #[0, [1, 2], 2]print b    #[0, [1, 2], 2]print c    #[0, [1, 2], 3]c[1][0] = 10print a    #[0, [10, 2], 2]print b    #[0, [10, 2], 2]print c    #[0, [10, 2], 3]a[1][0]=20 #可变对象print a    #[0, [20, 2], 2]print b    #[0, [20, 2], 2]print c    #[0, [20, 2], 3]a[0] = 3   #不可变对象print a    #[3, [20, 2], 2]print b    #[3, [20, 2], 2]print c    #[0, [20, 2], 2]

a和c是单独的列表对象,但是他们包含的公共元素是共享的,修改a的元素就会修改c(可变类型才会变哦,如果是不可变类型会新建对象的).

  • 深复制将创建一个新对象,并且递归地复制它包含的所有对象.可以使用copy.deepcopy()完成该工作.
import copya = [0,[1,2]]b = copy.deepcopy(a)b.append(2)print a    #[0, [1, 2]]print b    #[0, [1, 2], 2]b[1][0] = 10print a    #[0, [1, 2]]print b    #[0, [10, 2], 2]b[0] = 3print a    #[0, [1, 2]]print b    #[3, [10, 2], 2]

5 数据类型

None Type(None无任何属性,值为false) 数字 int,Long,float,cmplex,bool 序列 str,unicode,list,tuple,xrange 映射 dict 集合 set(可变集合),frozenset(不可变集合)

5.1 None

None类型表示一个null对象,如果一个函数没有显式地返回值,则返回None,如果None在布尔表达式求值时为False。

5.2 序列

序列表示索引为非负值整数的有序对象集合(list,tuple,str).字符串是字符的序列,而列表和元组是任意Python对象的序列,字符串和元组是不可变的,而列表支持插入,删除,替换元素.索引序列都支持迭代.

1) 序列通用操作

  1. s[i]
  2. s[i:j] 切片,返回s[i]至s[j-1]的元素
  3. s[i:j:step],返回s[i],s[i+step],s[i+2*step],…..直至i + n * step >= j,如a = range(10) a[0:5:2] = [0,2,4],
    如果i < j,step < 0,则返回[],(step不能为0)
  4. len(s)
  5. min(s),max(s)
  6. sum(s)
  7. all(s),检查s中所有项是否为True
  8. any(s),检查s中任意项为True,有一个元素为真则返回True
  9. s[i] = value
  10. s[i:j] = t,切片赋值,
  11. s[i:j:step],扩展切片赋值
a = range(5)print a[0:5:2]         #[0,2,4]print a[0:5:-1]        #[]print a[4:0:-1]        #[4,3,2,1]a = range(5)a[0:2]  = [10]print a                #[10,2,3,4]a[0:3]  =  range(10)   #[1,2,3,4,5,6,7,8,9,4]a = range(5)a[0:5:2] = [10,20,30]  #个数必须相同print a                #[10, 1, 20, 3, 30]

2) 列表,特有的函数

内置函数list(s)可以将任意可迭代对象转换为列表,如果s已经是一个列表,则该函数构造的新列表是s的一个浅复制.

list(s) 将s转换为一个列表,浅复制 s.append(x) x添加到s尾部 s.extend(x) 将列表x添加到x尾部 s.count(x) 计算s中x的出现次数 s.index(x) 搜索s中首次出现的x,并且返回索引,如果没有则会触发异常 s.insert(i,x) 在索引i处插入x s.pop([i]) 返回索引i处的元素并删除,如果省略i则返回最后一个元素并且删除 s.remove(x) 从s中搜索x并删除 s.reverse() 翻转s s.sort(cmp=None, key=None, reverse=False) cmp比较规则,key在进行比较之前应用于每个元素的函数,reverse是否反转
a = [0,5,3,6,9,4]f = lambda a:a%8a.sort(key = f)#[0, 9, 3, 4, 5, 6]

3) 字符串,特有的函数

通用操作虽然都是字符串实例,但是他们并不会修改原始的字符串数据(因为是不可变类型啊).

可利用help(str)查看所有方法

操作 解释 return s.capitalize(),capitalize = 以大写字母写 首字母大写 string s.center(width[, fillchar]) 在长度为width的字段内将字符串s居中,fillchar是填充字符(默认为空格),如果width还没有字符串本身长的话直接返回字符串s本身 string s.count(sub[, start[, end]]) 返回sub在s中出现的次数,start,end为s的范围 int s.decode([encoding[,errors]]) 编码,errors为出现错误时候的处理情况(默认为’strict’,还有’ignore’, ‘replace’ and’xmlcharrefreplace’) object s.encode([encoding[,errors]]) 解码 object s.endswith(suffix[, start[, end]]) 检查字符串s是否以suffix结尾 bool s.expandtabs([tabsize]) 使用空格替换制表符 string s.find(sub [,start [,end]]) 找到指定的子串首次出现的位置,未找到返回-1 int s.format(*args, **kwargs) 格式化s string s.index(sub [,start [,end]]) 找到指定的子串首次出现的位置,否则报异常 int s.isalnum() 检查所有字符是否都为字母或者数字 bool s.isalpha() 检查所有字符是否都为字母 bool s.isdigit() 检查所有字符是否都为数字 bool s.islower() 检查所有字符是否都为小写 bool s.isspace() 检查所有字符是否都为空白 bool s.istitle() 检查字符串是否为标题字符串(每个单词的首字母大写) bool s.isupper() 检查所有字符是否都为大写 bool s.join(iterable) 使用s作为分隔符连接迭代器中的字符串(必须为字符串) string s.ljust(width[, fillchar]) 在长度为width的字符串内左对齐s,右侧用fillchar来填充 string s.lower() 转化为小写 string s.lstrip([chars]),strip = 剥夺,去掉 从索引0处开始,去掉字符串s中出现在chars中出现的字符,直至s中的字符不在chars中,chars默认为空格(从左侧开始,去掉s中出现在chars中的字符,当s中出现了不在chars中的字符,则停止,详细使用见代码) string s.partition(sep),partition = 划分,分割,区分 使用seq将字符串s划分,返回(head,seq,tail),找到后停止查找,如果未找到seq,则返回(s,”,”),详见代码 (head, sep, tail) s.replace(old, new[, count]) 将出现在s中的old子串用new替换,count为次数,默认为全部替换 string s.rfind(sub [,start [,end]]) 找到一个子串最后出现的位置,未找到返回-1 int s.rindex(sub [,start [,end]]) 找到一个子串最后出现的位置,否则报错 int s.rjust(width[, fillchar]) 在长度为width的字符串内右对齐s,左侧用fillchar来填充 string s.rpartition(sep) s.partition(sep)相反 string s.rsplit([sep [,maxsplit]]) 从右侧,将s用sep拆分,如果省略了maxsplit则结果与split一样,(划分方向不一样) list s.rstrip([chars]) s.lstrip([chars])相反 string s.split([sep [,maxsplit]]) 从左侧,将s用sep拆分,maxsplit为划分次数 list s.splitlines(keepends=False) 将字符串分为一个行列表,如果keepends为1,则保留最后的换行符(以’\n’分割) list s.startswith(prefix[, start[, end]]) 检查s是否以prefix开头 bool s.strip([chars]) 删除s的开头和结尾出现在chrs中的字符,如果出现了一个不匹配的则停止 string s.swapcase() 将大写转换为小写,小写转换为大写 string s.title() 将s转换为标题格式,即每个单词的首字母大写 string s.translate(table [,deletechars]) 根据table给出的表(包含256个字符)转换string的字符,要过滤掉的字符放在deletechars中(感觉有点像加密- -) string s.upper() 转化为大写 string s.zfill(width) 在s左边填充0,直至宽度为width,和rjust(width,’0’)功能一样a,如果width没有s长的话直接返回s string
a = '123123'          b = '1234123'c = ' 123123'd = '123444451\n222\n2'#测试lstrip([chars])print a.lstrip()      #123123print c.lstrip()      #123123,去掉了空格print a.lstrip('123') #空,去掉了123123print b.lstrip('123') #4123,去掉了123print c.lstrip('123') # 123123,啥都没去掉#测试partitionprint a.partition('23') #('1', '23', '123')print a.partition('3')  #('12', '3', '123')#rsplitprint b.rsplit('3')     #['12', '12', '']print b.rsplit('3')     #['12', '412', '']#splitlinesprint d.splitlines()    #['123444451', '222', '2']#formata = "{0}-{1}-{1}-{2}"a.format(4,5,6)         #'4-5-5-6'

4) xrange()

xrange([i,]j[,step])创建的对象表示一个整数范围k,如果i<= k < j.

i,step是可选的默认值为0和1.

很像list,但是并不是list,不支持切片等操作

a = list(xrange(0,10,2))  #[0,2,4,6,8]print type(a)             #<type 'xrange'>

5) 映射类型dict

dict,无序,任何不可变对象都可以用作字典键值,包含可变对象的列表,字典,元组不能作为键值,因为字典类型要求键值保持不变.

a = ([1,2],3)     #a是元组不可变print id(a[0])    #48835016print id(a[0][0]) #31359704a[0][0] = 100print id(a[0])    #48835016 与上述一样print id(a[0][0]) #31361312,改变了哦print a           '''([100,2],3),我擦改变了!因为tuple是不可变类型,a[0]未改变,符合tuple要求,但是list是可变类型啊,只要不改变a[0]的引用即可(a[0] = range(5)这样是不可以的哦),对list内部的操作是可以的(如a[0].append(3).这就是为什么键值不能为包含可变类型的不可变类型的对象'''a[0].append(3)print a            #([100, 2, 3], 3)

dict内置方法

内置方法 含义 len(D) 键-值个数 D[k] 键k对应的值 D[k] = x 键k的值改为x del D[k] 删除键k k in D 如果k在D的键中返回True D.clear() 删除所有元素 D.copy() 浅复制字典的副本 dict.fromkeys(seq,val = None) 创建一个新字典,seq(list,tuple)中的元素作为键,值为val D.get(k,default = None) 如果键k在D中则返回对应的值,否则返回default D.has_key(k) 查看键k是否在D中 D.items() 返回由(key,value)组成的list D.iteritems() 返回由(key,value)组成的迭代器 D.iterkeys() 返回由key组成的迭代器 D.itervalues() 返回由value组成的迭代器 D.keys() 返回由key组成的list D.pop(k,[,default]) 如果找到了D[k],则返回D[k]并删除,否则,如果给了default的值则返回default,如果没有提供,则引发KeyError异常 D.popitem() 随机删除一个key-value,并返回成一个元组 D.setdefault(k[,d]) 如果找到了D[k],返回,否则返回d,并将D[k] = d D.update(D2) 将D2中的所有对象添加到D中 D.values() 返回由value组成的list D.viewitems() 查看所有键-值的方法 D.viewkeys() 查看所有键的方法 D.viewvalues() 查看所有值的方法

6) 集合

集合是唯一项的无序集,无切片操作,放入集合的项目必须是不可变的.

set,可变集合

frozenset,不可变集合

函数 含义 s.copy() 制作s的一份副本,浅复制 s.different(t) 差集,在s不在t s.difference_update(t) 删除s中所有在t中出现的元素 s.discard(mem) 删除s中的mem,如果mem不在s中,不作任何操作 s.intersection(t) 交集 s.intersection_update(t) 将s更新为s与t的交集 s.isdisjoint(t) 如果s和t没有相同项,则返回True s.issubset(t) 如果s是t的子集,返回True s.issuperset(t) 如果s是t的一个超集,返回True s.pop() 返回集合中的任意一个元素,并删除 s.remove(m) 删除m,如果m不在s,则报出异常 s.symmetric_difference(t) s与t的对称差集 s.symmetric_difference_update() 将s更新为s与t的对称差集 s.union() 求并集 s.update(t) 将t中所有的元素添加到s中,t可以是一个集合,一个序列,一个可迭代的任意对象

5.3 表示程序结构的内置类型

在Python中,函数,类,模块都可以当做数据操作的对象.

类型分类 类型名称 描述 可调用 types.BuiltinFunctionType 内置方法或函数 可调用 type 内置类型和类的类型 可调用 object 所有类型和类的祖先 可调用 types.FunctionType 用户定义的函数 可调用 types.MethodType 类方法 模块 types.ModuleType 模块 类 object 所有类型和类的祖先 类型 type 内置类型和类的类型

1) 可调用类型

  1. 用户自定义函数,具有如下属性

    def f():

    ​ pass

属性 描述 结果 f.__name__ 函数名称 ‘f’ f.__dict__ 包含函数属性的字典 {} f.__code__ 字节编译的代码

2) 类,类型与实例

定义类的时候,通常会生成一个type类型的对象

class Foo(object):    passtype(Foo)  # <type 'type'>

下表表示一个类型对象Foo = t的常用属性

属性 描述 t.__doc__ 文档字符串 t.__name__ 类名称 t.__bases__ 由基类组成的元组 t.__dict__ 保存类方法和变量的字典 t.__module__ 定义类的模块名称,也就是文件名字,如果是在本本文件调用的话就是__main__ t.__abstractmethods__ 抽象方法名称的集合,如果不存在抽象方法,就是未定义

下面为实例 i = Foo()的特殊属性

i.__class__ 实例所属的类 i.__dict__ 保存实例数据的字典

__dict__属性通常用于存储与一个实例相关的所有数据.就像i.var = value,这样的值就会保存在dict里面.但是如果用户使用的类使用了__slots__,就会使用一种更加有效的内部表示,实例也不会有__dict__属性.

__slots__是一个类变量,由一序列型对象组成,由所有合法标识构成的实例属性来表示.任何试图创建其名不在__slots__中的名字的实例属性都将导致AttributeError异常.

3) 模块

模块类型就是一个容易,可保存使用import语句加载的对象.例如,import foo,就会把名称foo模块的属性赋给调用的模块.可用属性如下:

属性 描述 m.__doc__ 模块文档字符串 m.__dict__ 模块相关的字典 m.__name__ 模块名称 m.__file__ 用于加载模块的文件 m.__path__ 完全限定包名,只在模块对象引用包时定义

5.4 对象行为和特殊方法

Python中的对象通常根据它们的行为和实现的功能进行分类.例如,所有序列类型放在一组,如list,tuple,因为他们都支持一系列相同操作,如s[n],len(s)等.所有基本的解释器操作都通过特殊的对象方法来实现.

特殊的方法名称前后始终带有双下划线__.当程序执行时,这些方法都由解释器自动触发.如x + y被映射为内部方法 x.__add__(y),x[k]映射为x.__getitem__(k).

每种数据类型的行为完全取决于它实现的一组特殊方法.

《对象行为完全取决于特殊方法啊= =》

1) 对象的创建与销毁

方法 描述 __new__(cls[,*args[,**kwargs]) 创建新实例时调用的类方法 __init__(self[,*args[,**kwargs]) 初始化新实例时调用 __del__(self) 销毁实例时候调用

调用A(args)创建对象时候,会进行以下步骤:

  1. x = A.__new__(A,args)
  2. is isinstance(x,A): x.__init__(args)

自定义的对象中,很少定义__new__()或者__del__()方法.

  • new通常只定义在元类或继承不可变类型之一的用户自定义对象中.
  • del方法只在有某种关键资源管理问题的情况才会定义,如释放锁定或关闭连接.

2) 对象的字符串表示

方法 描述 __format__(self,format_spec) 创建格式化后的表示 __repr__(self) 创建对象的字符串表示 __str__(self) 创建简单的字符串表示

__repr__(),通常返回一个表达式字符串,可对该字符串重新求值以重新创建对象.

如果无法创建字符串表达式,repr()返回一个\<_message>形式的字符串

a = range(3)  #[0,1,2]s = repr(a)   #'[0,1,2]'b = eval(s)   #[0,1,2]class a(object):    passb = a()print a.__repr__()  # errorprint b.__repr__()  #'<__main__.a object at 0x0000000002EF7EF0>'

__str__()与__repr__()的区别是它返回的字符串更加简明易懂.如果该方法未定义就会调用__repr__()方法

__format__ , “{0}a{0}b{1}”.format(123,456,789) 等价于

“{0}a{0}b{1}”.__format__(123,456,789)

3) 对象比较与排序

对象测试与散列的特殊方法.

方法 属性 __bool__(self) 用于真值测试,返回值为True或False.如果该方法未定义,Python将调用__len__()方法来确定其对象的真值. __hash__(self) 定义在要作字典中键的对象上.如果两个对象比较厚相等,作为返回值得整数应该完全相同.可变对象不应该定义该方法,因为对一个对象所做的任何改动都将改变散列值,从而在后续的字典查找中无法定位对象.

用于比较的方法见下表:

方法 结果 __lt__(self,other) self < other __le__(self,other) self <= other __gt__(self,other) self > other __ge__(self,other) self >= other __eq__(self,other) self == other __ne__(self,other) self < other

4) 类型检查

方法 结果 __instancecheck__(cls,object) isinstance(object,cls) __subclasscheck__(self,other) issubclass(sub,cls)

5) 属性访问

方法 描述 __getattribute__(self,name) 返回self.name __getattr__(self,name) 返回属性self.name,如果通过常规属性查找未找到属性,则引发AttributeError异常 __setattr__(self,name,name) 设置self.name = value __delattr__(self,name) 删除属性self.name

访问属性时始终会调用__getattribute__()方法,如果找到属性则返回之,否则调用__getattr__()方法来触发异常.设置属性会调用__setattr__()方法,删除属性时候则会调用__delattr__()方法.

6) 属性包装与描述符

描述符的__get__(),__set__()和__delete__()方法用于同类型的__getattribute__(),__setattr__(),__delattr__()方法进行交互.如果在用户自定义类的主体中放入一个描述符对象的实体,这种交互就会发生.

7) 序列与映射方法

如果对象要模拟序列和映射对象的行为,用下表的方法.

方法 描述 __len__(self) 返回self的长度 __getitem__(self,key) 返回self[key] __setitem__(self,key,value) 设置self[key] =value __delitem__(self,key) 删除self[key] __contains__(self,obj) 如果在obj在self中,则返回True,否则False
a = [0,1,2,3,4,5,6]len(a)         #a.__len__()a[2]           #a.__getitem__(2)a[0:4]         #a.__getitem__(slice(0,4,None)),slice对象描述切片范围的属性a[1] = 7       #a.__setitem__(1,7)del a[1]       #a.__delitem__(1)5 in a         #a.__contains__(5)

8) 迭代器

如果对象obj支持迭代,它必须提供方法obj.__iter__(),该方法返回一个迭代器对象.迭代器对象iter必须返回一个方法iter.next(),该方法返回下一个对象,迭代结束引发异常.

class A(object):    def __init__(self):        self.num = 10    def __iter__(self):        return self    def next(self):        if self.num > 0:            self.num -= 1            return self.num        else:            raise StopIterationa = A()b = iter(a)print b.next()  # 9for i in b:    print i     #8,7,6,5,4,3,2,1,0#for遇到StopIteration会停止循环

9) 可调用接口

对象可提供__call__(self[,*arg[,**kwargs])方法可模拟函数的行为.如果一个对象x提供了该方法,就可以像函数一样调用它.就是说x(arg1,arg2….)等同于调用了x.__call__(self,arg1,arg2…).模拟函数的对象可以用于创建仿函数或者代理.

10) 上下文管理协议

with operate as var:

​ statements

执行with语句时,就会调用__enter__()方法,该方法的返回值将被放入var中,离开with语句的时候回调用__exit__()方法.__exit__()方法接收当前异常的类型、值和跟踪作为参数.如果没有要处理的错误,所有三个值都将被置为None.

11) 对象检查dir

__dir__(self)获得对象可用函数名称列表.

0 0
原创粉丝点击