参考链接:https://www.cnblogs.com/wupeiqi/p/4766801.html
一、面向对象编程
面向对象有两个非常重要的概念,类和对象。
具有相似特征行为的事物的集合统称为类
对象是根据类创建的,一个类可以对应多个对象。
关于类:
1)类的定义
使用class关键字来声明一个类,基本格式如下:
class 类名:
类的属性
类的方法
根据类创建对象的语法格式如下:
对象名=类名()
要想给对象添加属性,可以通过如下方式:
对象名.新的属性名=值
2)类的声明
声明函数
声明类
class Person: #定义一个人类
role = 'person' #人的角色属性都是人
def walk(self): #人都可以走路,也就是有一个走路方法,也叫动态属性
print("person is walking...")
3)类的作用
属性引用(类名.属性)
class Person: #定义一个人类
role = 'person' #人的角色属性都是人
def walk(self): #人都可以走路,也就是有一个走路方法
print("person is walking...")
print(Person.role) #查看人的role属性
print(Person.walk) #引用人的走路方法,注意,这里不是在调用
实例化:类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征
class Person: #定义一个人类
role = 'person' #人的角色属性都是人
def __init__(self,name):
self.name = name # 每一个角色都有自己的昵称;
def walk(self): #人都可以走路,也就是有一个走路方法
print("person is walking...")
print(Person.role) #查看人的role属性
print(Person.walk) #引用人的走路方法,注意,这里不是在调用
属性的两种定义方式
装饰器 :即在方法上应用装饰器
静态字段 即在类中定义值为property对象的静态字段
装饰器方式:在类的普通方法上应用@property装饰器
我们知道Python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。( 如果类继object,那么该类是新式类 )
经典类,具有一种@property装饰器
View Code
新式类,具有三种@property装饰器
View Code
注:经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法
新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法
由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
静态字段方式,创建值为property对象的静态字段
当使用静态字段的方式创建属性时,经典类和新式类无区别
View Code
property的构造方法中有四个参数
第一个参数是方法名,调用 对象.属性 时自动触发执行方法
第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
第四个参数是字符串,调用 对象.属性.__doc__ ,此参数是该属性的描述信息
由于静态字段方式创建属性具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
注意:Python WEB框架 Django 的视图中 request.POST 就是使用的静态字段的方式创建的属性
所以,定义属性共有两种方式,分别是【装饰器】和【静态字段】,而【装饰器】方式针对经典类和新式类又有所不同。
4)类成员的修饰符
对于每一个类的成员而言都有两种形式:
公有成员,在任何地方都能访问
私有成员,只有在类的内部才能方法
私有成员和公有成员的定义不同:私有成员命名时,前两个字符是下划线。(特殊成员除外,例如:init、call、_dict
class C:
def __init__(self):
self.name = '公有字段'
self.__foo = "私有字段"
私有成员和公有成员的访问限制不同:
静态字段
公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
私有静态字段:仅类内部可以访问;
普通字段
公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问
私有普通字段:仅类内部可以访问;
ps:如果想要强制访问私有字段,可以通过 【对象._类名__私有字段明 】访问(如:obj._C__foo),不建议强制访问私有成员。
方法、属性的访问于上述方式相似,即:私有成员只能在类内部使用
ps:非要访问私有属性的话,可以通过 对象._类__属性名
类的特殊成员
介绍了Python的类成员以及成员修饰符,从而了解到类中有字段、方法和属性三大类成员,并且成员名前如果有两个下划线,则表示该成员是私有成员,私有成员只能由类内部调用。无论人或事物往往都有不按套路出牌的情况,Python的类成员也是如此,存在着一些具有特殊含义的成员,详情如下:
-
__ doc__表示类的描述信息
-
__ module__ 和 __ class__
__ module__ 表示当前操作的对象在那个模块
__ class__ 表示当前操作的对象的类是什么
3. __ init__构造方法,通过类创建对象时,自动触发执行。
- __ del__析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
- __ call__对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
- __ dict__类或对象中的所有成员
类的普通字段属于对象;类中的静态字段和方法等属于类,即:
class Province:
country = 'China'
def __init__(self, name, count):
self.name = name
self.count = count
def func(self, *args, **kwargs):
print 'func'
#获取类的成员,即:静态字段、方法、
print Province.__ dict__
#输出:{‘country’: ‘China’, ‘__ module__’: ‘__ main__’, ‘func’: <function func at 0x10be30f50>, ‘__ init__’: <function init at 0x10be30ed8>, ‘__ doc__’: None}
obj1 = Province(‘HeBei’,10000)
print obj1.__ dict__
#获取 对象obj1 的成员
#输出:{‘count’: 10000, ‘name’: ‘HeBei’}
obj2 = Province(‘HeNan’, 3888)
print obj2.__ dict__
#获取 对象obj1 的成员
#输出:{‘count’: 3888, ‘name’: ‘HeNan’}
- __ str__如果一个类中定义了__ str__方法,那么在打印 对象 时,默认输出该方法的返回值。
8、__ getitem__、__ setitem__、__ delitem__用于索引操作,如字典。以上分别表示获取、设置、删除数据
class Foo(object):
def __getitem__(self, key):
print '__getitem__',key
def __setitem__(self, key, value):
print '__setitem__',key,value
def __delitem__(self, key):
print '__delitem__',key
obj = Foo()
result = obj['k1'] # 自动触发执行 __ getitem__
obj['k2'] = 'wupeiqi' # 自动触发执行 __ setitem__
del obj['k1'] # 自动触发执行 __ delitem__
9、getslice、setslice、delslice 该三个方法用于分片操作,如:列表
class Foo(object):
def __getslice__(self, i, j):
print '__getslice__',i,j
def __setslice__(self, i, j, sequence):
print '__setslice__',i,j
def __delslice__(self, i, j):
print '__delslice__',i,j
obj = Foo()
obj[-1:1] # 自动触发执行 __ getslice__
obj[0:1] = [11,22,33,44] # 自动触发执行 __ setslice__
del obj[0:2] # 自动触发执行 __ delslice__
- __ iter__ 用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __ iter__
以上步骤可以看出,for循环迭代的其实是 iter([11,22,33,44]) ,所以执行流程可以变更为:
obj = iter([11,22,33,44])
for i in obj:
print i
- __ new__ 和 __ metaclass__
class Foo(object):
def __init__(self):
pass
obj = Foo() # obj是通过Foo类实例化的对象
obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。
如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。
print type(obj) # 输出:<class '__ main__.Foo'> 表示,obj 对象由Foo类创建
print type(Foo) # 输出:<type 'type'>
表示,Foo类对象由 type 类创建
所以,obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。
那么,创建类就可以有两种方式:
a). 普通方式
class Foo(object):
def func(self):
print 'hello wupeiqi'
b).特殊方式(type类的构造函数)
def func(self):
print 'hello wupeiqi'
Foo = type('Foo',(object,), {'func': func})
#type第一个参数:类名
#type第二个参数:当前类的基类
#type第三个参数:类的成员
==》 类 是由 type 类实例化产生
类中有一个属性 __ metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __ metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程