Python进阶-面向对象
类的成员
类的成员可以分为三类:字段、方法、属性
一:字段:
普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同
- 普通字段属于对象
- 静态字段属于类
字段的定义和使用
class Province:
# 静态字段
country = '中国'
def __init__(self,name):
# 普通字段
self.name = name
# 直接访问普通字段
obj = Province('北京')
print obj.name
# 直接访问静态字段
print Province.country
点睛:
1:谁来调用:
从上面可以看出普通字段需要通过对象来访问,静态字段通过类来调用。
2:存储的位置
- 静态字段只存在把内存中一份,存在类的内存中
- 普通字段在每个对象中都要创建一份。
通过类创建对象的时候,如果每个对象都具有相同的字段,那么就使用静态字段
二:方法
普通方法、静态方法、类方法。三种方法在内存中都属于类,区别在于调用方式不同
- 普通方法:由对象调用,至少一个self参数,执行普通方法时,自动将调用该方法的对象赋值给self
- 类方法:由类调用,至少一个cls参数,执行类方法时,自动将调用该方法的类赋值给cls
- 静态方法:由类调用,无默认参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Foo: # 初始化类 def __init__(self): pass # 定义普通方法,至少有一个self参数 def p(self): print '普通方法' # 定义类方法,至少有一个cls参数 @classmethod def q(cls): print '类方法' # 定义静态方法 @staticmethod def w(): print '静态方法' # 调用普通方法 a = Foo() ret = a.p() # print ret # 调用类方法 Foo.q() # 调用静态方法 Foo.w() |
---|
点睛:
相同点:对于所有的方法而言,均属于类中,所以在内存中也之保存一份
不同点:方法调用者不同,调用方法时,自动传入的参数不同
三:属性
1:属性的基本使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class Foo: def func(self): # print 'func' return '方法调用的返回值' # 定义属性 @property def prop(self): # print 'prop' return '属性调用的返回值' # 调用方法 obj = Foo() ret = obj.func() print ret # 调用属性 ret1 = obj.prop print ret1 |
---|
点睛:
- 定义时,在普通方法的基础上在上面添加@property装饰器
- 属性仅有一个self参数
- 调用时,无需括号
方法:
obj = Foo()
ret = obj.func()
属性:
obj = Foo()
ret = obj.prop
属性存在的意义:访问属性时,可以制造出和访问字段完全相同的假象
实例:
对于主机列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第M条到第N条的所有数据,这个分页功能包括:
- 根据用户请求的当前和总数据条数计算出m和n
- 根据m和n去数据库请求数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Pager: def __init__(self,current_page): # 用户当前请求的页面 self.current_page = current_page # 每页默认显示10条 self.per_items = 10 # 定义属性 @property def start(self): val = (self.current_page - 1) * self.per_items return val @property def end(self): val = self.current_page * self.per_items return val # 调用属性 p = Pager(2) print p.start print p.end # 结果: # 10 # 20 |
---|
2:属性的两种定义方式
装饰器、静态字段
装饰器:在方法上应用装饰器
静态字段:在类中定义值为property对象的静态字段
装饰器方式:
经典类,具有一种@property装饰器
# 定义类
class Foo:
@property
def fun(self):
return 'caoxiaojian'
# 调用属性
obj = Foo()
ret = obj.fun
print ret
# 自动执行 @property修饰的fun方法,并获取方法的返回值
新式类,具有三种@property装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Goods(object): @property def price(self): print '@property' @price.setter def price(self,value): print '@price.setter',value @price.deleter def price(self): print '@price.deleter' # 调用 obj = Goods() obj.price # 自动执行@property修饰的price方法,并获取方法的返回值 obj.price = 123 # 自动执行@price.setter修饰的price方法,并将123赋值给方法的参数 del obj.price # 自动执行@price.deleter修饰的price方法 执行结果: @property @price.setter 123 @price.deleter |
---|
注释:
经典类中的属性只用一种访问方式,其对应被@property修饰的方法
新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法
因为新式类有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为同一个属性:获取、修改、删除
实例讲解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
class Goods(object): def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self,value): # 设置原始价格 self.original_price = value @price.deleter def price(self,value): # 删除原始价格 del self.original_price # 调用 obj = Goods() # 获取商品价格 obj.price # 设置原始价格 obj.price = 3000 # 删除原始价格 del obj.price |
---|
静态字段方式:
创建值为property对象的静态字段
当使用静态字段的方式创建属性时,经典类和新式类无区别
1 2 3 4 5 6 7 8 9 |
class Foo: def get_bar(self): return 'caoxiaojian' BAR = property(get_bar) obj = Foo() # 自动调用get_bar方法,并获取方法的返回值。 ret = obj.BAR print ret |
---|
property的构造方法中有个四个参数
- 第一个参数是方法名,调用对象.属性时自动触发执行方法
- 第二个参数是方法名,调用对象.属性 = xxx时自动触发执行方法
- 第三个参数是方法名,调用del 对象.属性时自动触发执行方法
- 第四个参数是字符串,调用对象.属性.__doc__此参数是该属性的描述信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Foo: def get_bar(self): return 'caoxiaojian' # 必须有两个参数 def set_bar(self): return 'set value' + value def del_bar(self): return 'caoxiaojian===2' BAR = property(get_bar, set_bar, del_bar,'description......') obj = Foo() print obj.BAR # 自动调用第一个参数中定义的方法:get_bar obj.BAR = "caogaotian" # 自动调用第二个参数中定义的方法:set_bar方法,将"caogaotian" 当作参数传入 print obj.BAR del obj.BAR # 自动调用第三个参数中定义的方法:del_bar print obj.del_bar() obj.BAR.__doc__ # 自动调用第三个参数中设置的值:'description......' ''' 结果输出: caoxiaojian caogaotian caoxiaojian===2 ''' |
---|
类成员的修饰符
两种形式:
- 私有成员:只有在类的内部才能访问的方法
- 公有成员:在任何地方都能访问
定义的不同:
私有成员命名时,前面两个字符是下划线。(特殊成员除外,例如:__init__等)
class C:
def __init__(self):
self.name = '公有字段'
self.__name = '私有字段'
私有成员和公有成员的访问限制不同
静态字段
- 公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
- 私有静态字段:仅类内部可以访问
公有静态字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class C: name = '公有静态字段' def func(self): print C.name class D(C): def func_1(self): print C.name # 直接使用类访问 C.name # 类内部访问 obj = C() obj.func() # 派生类内部访问 obj_1 = D() obj_1.func_1() ''' 结果打印: 公有字段 公有字段 ''' |
---|
私有静态字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class C: __name = '公有静态字段' def func(self): print C.__name class D(C): def func_1(self): print C.__name # 类中访问 # C.__name # 错误 # 类内部访问 obj = C() obj.func() # 派生类中访问 # obj_1 = D() # 错误 # obj_1.func_1() |
---|
普通字段
- 公有普通字段:对象、类、派生类都可以访问
- 私有普通字段:只能在类内部访问
公有普通字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
class C: def __init__(self): self.foo = '公有字段' def func(self): # 在类内部调用访问 print self.foo class D(C): def show(self): # 在派生类中调用访问 print self.foo obj = C() # 通过对象访问 print type(obj.foo) print obj.foo print '===========' # 类的内部访问 obj.func() print '===========' obj_1 = D() # 在派生类中访问 obj_1.show() ''' 结果打印: <type 'str'> 公有字段 =========== 公有字段 =========== 公有字段 ''' |
---|
私有普通字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class C: def __init__(self): self.__foo = '私有普通字段' def func(self): # 类的内部调用访问 print self.__foo class D(C): def show(self): # 在派生类中调用访问 print self.__foo obj = C() # obj.__foo # 通过对象访问:报错 obj.func() # 通过类内部访问 obj_1 = D() #obj_1.show() # 通过派生类调用访问: 报错 |
---|
类的特殊成员
1:__doc__
表示类的描述信息
class C:
"""
这是描述信息,你看什么看??
"""
def func(self):
pass
print C.__doc__
# 输出:这是描述信息,你看什么看??
2:__module__和__class__
__module__:表示当前操作的对象在哪个模块
__class__: 表示当前操作的对象的类是哪一个
在tmp模块下面有test.py和test1.py
test.py
class C:
def __init__(self):
self.name = 'caoxiaojian'
test1.py
from test import C
# 根据导入的C类创建对象
obj = C()
# 获取对象中的模块名
print obj.__module__ # test
# 获取对象中的类名
print obj.__class__ # test.C
3:__init__
构造方法,通过类创建对象时,自动触发执行
class C:
def __init__(self,name):
self.name = name
self.age = 18
obj = C('caoxiaojian') # 自动执行类中的__init__方法
print obj.name
4:__call__
对象后面加括号,触发执行
点睛:
构造方法的执行是由创建对象触发的。即:对象名 = 类名()
__call__方法的执行由对象后面加括号触发的。即:对象()或者类名()()
class C:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print '__call__'
obj = C() # 触发__init__
obj() # 触发__call__
5:__dict__
类或对象中的所有成员
点睛:
类的普通字段属于对象,类中的静态字段和方法等属于类
class Province:
country = 'china'
def __init__(self,name,count):
self.name = name
self.count = count
def func(self, *args, **kwargs):
print 'func===func'
# 获取类中的成员:静态字段和方法
print Province.__dict__
# {'country': 'china', '__module__': '__main__', 'func': <function func at 0x021DA7F0>, '__init__': <function __init__ at 0x021DA870>, '__doc__': None}
# 调用类创建obj对象
obj = Province('shandong',100000)
print obj.__dict__
# {'count': 100000, 'name': 'shandong'}
# 调用类创建foo对象
foo = Province('beijing',20000)
print foo.__dict__
# {'count': 20000, 'name': 'beijing'}
类的分类:
经典类和新式类
# 经典类
class func:
def Foo(self):
pass
# 新式类
class func_new(object):
def Foo_new(self):
pass
点睛:
区别:就是在类的后面加个object
类的继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# 新式类 class D(object): # 经典类 #class D: def bar(self): print 'D.bar' class C(D): def bar(self): print 'C.bar' class B(D): pass class A(B,C): pass a = A() a.bar() ''' 经典类:深度优先 D.bar 新式类:广度优先 C.bar ''' |
---|
点睛:
经典类:深度优化
新式类:广度优化
- nginx反向代理+缓存开启+url重写+负载均衡(带健康探测)的部署记录
- [转自blueidea]像table一样布局div Ⅰ
- 如何对动态创建控件进行验证以及在Ajax环境中的使用
- 升级个人网站框架组件IBatisNet+Castle
- 如何在多线程中调用winform窗体控件
- gerrit代码简单备份方案分享
- svn代码发版的脚本分享
- 正则表达式提取指定内容
- mysql数据库误删除后的数据恢复操作说明
- 在.NET平台上运行Java程序-IKVM.NET入门
- ArraySegment<T>泛型结构示例
- SwitchButton 开关按钮 的多种实现方式
- SVN和Git对比梳理
- linux下expect环境安装以及简单脚本测试
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Mysql 如何实现全文检索,关键词跑分
- spring之操作数据库之使用NamedParameterJdbcTemplate(具名参数)
- 谷歌colab上安装百度paddlepaddle框架
- 谷歌colab运行paddlepaddle之手写数字识别
- 【python-leetcode112-树的深度遍历】路径总和
- spring之第一个spring程序
- 【python-leetcode437-树的深度遍历】路径总和Ⅲ
- 双指针--合并两个排序数组
- spring之事务的其它属性(隔离级别、回滚、只读、过期)(四)
- 二分查找
- 一文弄懂数组的和
- spring之基于xml文件来配置事务(五)
- hash算法的应用
- 树的遍历
- spring之事务的传播行为(三)