类的两种类型:
经典类:
- class Person():# 没有继承 object
- Pass
新式类:
- class Person(object):# 继承 object
- pass
面向对象技术简介
类(Class): 用来描述具有相同的属性和方法的对象的集合. 它定义了该集合中每个对象所共有的属性和方法. 对象是类的实例.
类变量: 类变量在整个实例化的对象中是公用的. 类变量定义在类中且在函数体之外. 类变量通常不作为实例变量使用.
数据成员: 类变量或者实例变量用于处理类及其实例对象的相关的数据.
方法重写: 如果从父类继承的方法不能满足子类的需求, 可以对其进行改写, 这个过程叫方法的覆盖(override), 也称为方法的重写.
实例变量: 定义在方法中的变量, 只作用于当前实例的类.
继承: 即一个派生类 (derived class) 继承基类 (base class) 的字段和方法. 继承也允许
把一个派生类的对象作为一个基类对象对待. 例如, 有这样一个设计: 一个 Dog 类型的对象派生自 Animal 类, 这是模拟 "是一个(is-a)" 关系(例图, Dog 是一个 Animal).
实例化: 创建一个类的实例, 类的具体对象.
方法: 类中定义的函数.
对象: 通过类定义的数据结构实例. 对象包括两个数据成员 (类变量和实例变量) 和方法
创建类
- #coding=utf-8
- class Employee(object):
- empCount = 0
- def __init__(self,name,salary):
- self.name = name
- self.salary = salary
- Employee.empCount += 1
- def displayCount(self):
- print("total employee",Employee.empCount)
- def displayEmployee(self):
- print("name:",self.name,",salary:",self.salary)
empCount 变量是一个类变量 (也叫静态变量), 它的值将在这个类的所有实例之间共享. 你可以在内部类或外部类使用 Employee.empCount 访问. 类中第一个方法 init() 是一种特殊方法, 被称做类的构造函数或初始化方法, 只要创建类的实例, 就会调用这个方法. 如果没显示定义这个方法, 默认会给一个空的构造方法. 类方法中参数中的 self, 代表实例本身, 相当于 java 中的 this 指针. 并且类中所有的方法中都必须有 self, 并且写在第一个参数位置. 所有类都是继承至基类 object.
类和对象在内存中的保存
类以及类中的方法在内存中只有一份, 而根据类创建的每一个对象都在内存中需要存一份
如上图所示, 根据类创建对象时, 对象中除了封装 name 和 age 的值之外, 还会保存一个类对象指针, 该值指向当前对象的类. 当通过 obj1 执行 [方法一] 时, 过程如下: 根据当前对象中的 类对象指针 找到类中的方法将对象 obj1 当作参数传给 方法的第一个参数 self
面向对象应用场景
函数式的应用场景 --> 各个函数之间是独立且无共用的数据
面向对象编程的应用场景→各个函数公用一组数据
封装 1
封装, 顾名思义就是将内容封装到某个地方, 以后再去调用被封装在某处的内容.
在使用面向对象的封装特性时, 需要:
将内容封装到某处
从某处调用被封装的内容
self 是一个形式参数, 当执行 obj1 = Foo('wupeiqi', 18 ) 时, self 等于 obj1
当执行 obj2 = Foo('alex', 78 ) 时, self 等于 obj2;
所以, 内容其实被封装到了对象 obj1 和 obj2 中, 每个对象中都有 name 和 age 属性, 在内存里类似于下图来保存:
调用封装的内容
调用被封装的内容时, 有两种情况:
通过对象直接调用
通过 self 间接调用
1, 通过对象直接调用被封装的内容
上图展示了对象 obj1 和 obj2 在内存中保存的方式, 根据保存格式可以如此调用被封装的内容: 对象. 属性名
2, 通过 self 间接调用被封装的内容执行类中的方法时, 需要通过 self 间接调用被封装的内容
通过对象直接调用
- #coding=utf-8
- class Foo:
- def init(self,name,age):
- self.name = name
- self.age = age
- obj1 = Foo("huhongiang",20)
- print(obj1.name)# 直接调用 obj1 对象的 name 属性
- print(obj1.age)# 直接调用 obj1 对象的 age 属性
- obj2 = Foo("alex",73)
- print(obj2.name)
- print(obj2.age)
通过 self 间接调用被封装的内容
- #coding=utf-8
- class Foo:
- def init(self,name,age):
- self.name = name
- self.age = age
- def detail(self):
- print(self.name)
- print(self.age)
- obj1 = Foo("huhongiang",20)
- obj1.detail()
- #python 将 obj1 参数传递给 self 参数, 即 obj1.detail(obj1), 此时方法内部 self == obj1, 所以 self.name == obj1.name, self.name 就是 huhongiang,self.age 就是 20
- obj2 = Foo("alex",73)
- obj2.detail()
类成员
字段
字段包括: 普通字段和静态字段, 他们在定义和使用中有所区别, 而最本质的区别是内存中保存的位置不同
普通字段属于对象
静态字段属于类
- #coding=utf-8
- class Province:
- # 静态字段, 类变量
- country = "中国"
- def init(self,name):
- # 普通字段
- self.name = name
- obj = Province("河北省")
- print(obj.name)# 直接访问普通字段
- print(Province.country)# 直接访问静态字段
静态字段在内存中只保存一份
普通字段在每个对象中都要保存一份
类变量可以被类和实例对象访问, 但是实例变量只能被实例对象访问
方法
方法包括: 普通方法, 静态方法和类方法, 三种方法在内存中都归属于类, 区别在于调用方式不同.
普通方法: 由对象调用; 至少一个 self 参数; 执行普通方法时, 自动将调用该方法的对象赋值给 self;
类方法: 由类调用; 至少一个 cls 参数; 执行类方法时, 自动将调用该方法的类复制给 cls;
静态方法: 由类调用; 无默认参数
示例:
- #coding=utf-8
- class Foo(object):
- def init(self,name):
- self.name = name
- # 普通方法, 需要默认的 self 参数
- def ord_func(self):
- print(self.name)
- print("普通方法")
- # 类方法, 需要默认 cls 参数, cls 代表类本身
- @classmethod
- def class_func(cls):
- print("类方法")
- # 静态方法, 不需要默认参数
- @staticmethod
- def static_func():
- print("静态方法")
- #return self.name# 静态方法不能访问实例变量, 静态方法可以访问类变量(静态变量)
- f = Foo("gloryroad")
- f.ord_func()# 对象调用普通方法, 不能用类调用
- Foo.class_func()# 直接用类名调用类方法
- Foo.static_func()# 直接用类名调用静态方法
- # 静态方法和类方法也可以由对象调用
- f.class_func()
- f.static_func()
- Foo.ord_func() #但是不能由类直接调用普通方法(实例方法)
- Foo.name #类也不能访问实例变量
相同点: 对于所有的方法而言, 均属于类 (非对象) 中, 所以, 在内存中也只保存一份.
不同点: 方法调用者不同, 调用方法时自动传入的参数不同
类的属性
Python 中的属性其实是普通方法的变种.
@property
定义时, 在普通方法的基础上添加 @property 装饰器; 定义时, 属性仅有一个 self 参数;
调用时, 无需括号
方法调用: foo_obj.func()
属性调用: foo_obj.prop
注意: 属性存在意义是: 访问属性时可以制造出和访问字段完全相同的假象, 属性由方法变种而来, 如果 Python 中没有属性, 方法完全可以代替其功能.
- #coding=utf-8
- class Foo(object):
- def func(self):
- print("func")
- # 定义属性
- @property
- def prop(self):
- return "gloryroad"
- foo_obj = Foo()
- foo_obj.func()
- print(foo_obj.prop)# 调用属性不需要括号
- @method_name.setter @method_name.deleter
定义时在普通方法的基础上添加 @method_name.setter 装饰器, 赋值操作时候自动执行被修饰的方法; 添加 @method_name.deleter 装饰器, del 删除
- #coding=utf-8
- class Goods(object):
- @property
- def price(self):
- print("@property")
- return "hhq"
- @price.setter
- def price(self,value):
- print("@price.setter")
- print(value)
- @price.deleter
- def price(self):
- print("@price.deleter")
- obj = Goods()br/>print(obj.price)# 自动执行 @property 修饰的方法, 并获得返回值
- obj.price = 123# 自动执行 @prirce_setter 修饰的方法, 并将 123 赋值方法的参数
- del obj.price# 自动执行 @price_deleter 修饰的方法
新式类中的属性有三种访问方式, 并分别对应了三个被 @property,@方法名. setter,@方法名. deleter 修饰的方法
来源: http://www.bubuko.com/infodetail-2932033.html