类的声明:
一、类的属性
(私有属性和公有属性)
(类属性)
二、类的方法
(构造方法、析构方法、自定义方法、特殊成员方法)
(静态方法、类方法、类属性)
三、类的继承
(方法和属性的继承,方法的重构)
(抽象类,多重继承)
四、类的多态
(实现接口的重用)
五、类的特殊装饰
(@staticmethod、@classmethod、@property)
六、类的来源和原类(metaclass)
七、反射
- 类的声明
使用class声明类,建议类名单词首字母大写。
“新式类”和“经典类”的区分在Python 3之后就已经不存在,在Python 3.x之后的版本,因为所有的类都派生自内置类型object(即使没有显示的继承object类型),即所有的类都是“新式类”。
新式类:
class Management(object): def add(): pass
经典类:
class Management: pass
- 类的属性
类的属性就是类定义的变量值。
公有属性:在类里直接定义的属性,它在类名下面直接定义。
调用:1、类中调用:类名.属性名 ,更改原公有属性值
2、实例调用:实例.属性名
class Management(object): num = 10 def add(self): Management.num +=10 # 类中调用公有属性并更改值,num=11 pass s1 = Management() s2 = Management() # 第一种情况:s1实例中调用公有属性,s2实例没有调用公有属性 s1.num +=1 Management.num += 2 """ <结果> s1不变,s2和Management都改变了 s1_num:11 s2_num:12 Manage_num:12 """ # 第二种情况:先调用s1实例公有属性,再通过S1调用add更改,然后再使用类更改 s1.num +=1 s1.add() Management.num += 2 """ <结果> 先调用的s1实例num依然不变,s2和Management都被修改了 s1_num:11 s2_num:22 Manage_num:22 """
问题:为什么修改num的值以后,实例s1和实例s2会有不同的结果呢 ?
因为公有属性查找的顺序是:先找实例的公有属性,没找到再找类里的公有属性
可以这样理解:Management相当于一个微信群,num是群里发的一张照片,S1和S2是群里面的两个人。
情况1:S1把照片存到本地,P了个双眼皮,S2说太难看了,我也不会P图,不保存。这个时候发照片的Management说我也觉得难看,把图撤回,重新发了一个P的图。S2就只能保存最新的图片。
情况2:S1找到Management说你的图太丑了,重新改一下吧,Management说好!撤回图片修改了~
私有属性:加两个下划线,__membername,编译的时候自动加上类名,变成_classname__membername,这种技术叫变量名压缩(mangling),以达到外部不能调用的目的。实际使用_classname__membername是可以调用的,但是不符合规定。标准方法是通过定义函数来获取。
class Classname(object): '''this is a demo!''' def __init__(self): self.__membername = 88 def read_membername(self): # 标准的外部访问方法,使用函数来读取私有属性。 return self.__membername s= Classname() print(s._Classname__membername) print(s.read_membername()) ''' <结果> 88 88 ------像下面的调用,会出现AttributeError错误------ print(s.__membername) '''
类属性: 类自带的属性,需要注意的是实例化的类属性,和原类的类属性不同。用上面的例子作演示。
属性 | 作用 | 示例 | 结果 |
__doc__ | 类的文档字符串 | print(s.__doc__) print(Classname.__doc__) |
this is a demo! this is a demo! |
__dict__ | 类的属性组成的字典 | print(s.__dict__) print(Classname.__dict__) |
{'_Classname__membername': 88} {'__init__':, '__module__': '__main__', '__doc__': '\nthis is a demo!\n', 'read_membername':} |
__name__ | 类的名字(字符串) | ##不能用于实例print(s.__name__ ) print(Classname.__name__ ) |
Classname |
__bases__ | 类的所有父类组成的元组 | #不能用于实例print(s.__bases__) print(Classname.__bases__) |
(,)为什么没有值?可能是编译器问题 |
__module__ | 类所属的模块 | print(s.__module__) print(Classname.__module__) |
__main__ __main__ |
__class__ | 类对象的类型 | print(s.__class__) print(Classname.__class__) |
待测 |
__slots__ |
限定类属性,在类属性位置定义 未在slots定义的属性都是非法属性 |
__slots__.('name','age','sexy') | 使用'name','age','sexy'的以外属性会报错 |
- 类的方法
类的方法就是类里面定义的函数。类的构造方法、析构方法、自定义类方法、静态方法、类方法、属性方法、特殊成员方法。
构造方法:__init__
实例化类的时候就会运行的函数。希望初始化的参数放置在init下面。(个人觉得,这个初始化参数可以是一切对象!)
class A(object): def instense(self): print("init obj A") class B(object): def __init__(self, para): self.init_para = para self.obj_A = A() self.num = 1 def show(self): print(self.init_para) self.obj_A.instense() print(self.num) haha = B("this is para") haha.show() ---------- this is para init obj A 1
析构方法:
__del__:销毁实例时,方法才会执行。
class Hello(object): def __del__(self): print("你删除了实例") # 在python上测试 instance = Hello() del instance # 当然也可以使用实例调用,但没有这么用的~~ instance.__del__()
自定义方法:
除去类中自带的以_下划线开头的函数,在类中定义一个函数,实现相应的功能。
class Person(object): def __init__(self,person_name, person_age)
静态方法:
@staticmethod,不需要访问类里的任何参数。所带的参数都是从外部传入的。
class Person(object): def __init__(self,person_name, person_age): self.name = person_name self.age = person_age @staticmethod def info(country): print(country)
类方法:
@classmethod,第一个参数必须是类属性。
class Person(object): country = "china" def __init__(self,person_name, person_age): self.name = person_name self.age = person_age @classmethod def info(country): print(country)
属性方法:
@property把一个函数变成一个静态属性
直接调用函数名字,不需要加括号,就能获取到函数返回值。一般用在不注重过程,只要结果的情况!
class Person(object): country = "china" def __init__(self,person_name, person_age): self.name = person_name self.age = person_age @property def health_point(self): print("HP:【{}】".format(self.age*2)) return self.age*2 P = Person("laowang",23) P.health_point # 不需要括号,看起来完全是一个属性,这就是属性方法
特殊成员方法:
方法 | 作用 | 示例 | 结果 |
__call__ |
默认未定义 类实例化后,调用实例运行的方法 |
p = Person() p() |
Person是类名 实例p没有调用函数,加()运行call方法 |
__str__ |
默认未定义,定义时必须有返回值 定义时,打印实例,输入str返回值 |
p = Person() print (p) |
Person是类名 打印实例p,运行str方法,打印返回值 |
__getitem__ | 用于索引操作,如字典。获取数据 |
p = Person() p['name'] |
自动运行getitem |
__setitem__ | 用于索引操作,如字典。赋值 |
p = Person() p['name'] = 'David' |
自动运行setitem |
__delitem__ | 用于索引操作,如字典。删除数据 |
p = Person() del p['name'] |
自动运行delitem |
__new__ |
类实例化时,执行__new__,并且会阻止 init运行,可以在new里调用init |
p = Person() | 参照例子二 |
__len__ | 待续 | ||
__cmp__ | 待续 |
'''例子一call\str\getitem\setitem\delitem方法''' class Person(object): def __call__(self): print("print call") def __str__(self): print("print str:",end='') return "1" def __getitem__(self,key): print("getitem:",key) def __setitem__(self,key,value): print('setitem:',key,value) def __delitem__(self,key): print('delitem:',key) p = Person() p() print(p) print('-----------') get = p['name'] p['name'] = 'David' del p['name']
'''例子二:__new__/__init__''' class Person(object): def __init__(self): print('this is init!') def __new__(self): print("this is new!") self.__init__(self) # 如果去掉这一行,init不能执行 p = Person()
类的来源和元类:
http://blog.jobbole.com/21351/中文版详细解答。下面写一个自己理解的简版的。
首先,类也是对象,可以:
1) 你可以将它赋值给一个变量
2) 你可以拷贝它
3) 你可以为它增加属性
4) 你可以将它作为函数参数进行传递
类也是是由type()这个函数创建的,type是类的类,类的爹。学名叫元类!
也许有人会问那为啥type()能查看到数据类型呢?因为数据类型在Python中都是类定义的,这也说明了,为什么数字,字符等等全是对象。
type格式:
type(类名,(父类元组),{属性字典},{方法词典}) , 父类元组可以没有;后面两个典省略时,默认值为None。
'''一言不合就上例子''' class Person(object): country = 'china' Person = type('Person',('object',),{'country':china})
未完待续。。。
- 类的继承
- 类的多态
- 反射
原文地址:http://blog.51cto.com/yishi/2072182