day7--面向对象进阶(内含反射和item系列)
一面向对象的结构和成员
1.1面向对象的结构
class A: company_name = '老男孩教育' # 静态变量(静态字段)
__iphone = '1353333xxxx' # 私有静态变量(私有静态字段) def __init__(self,name,age): #普通方法(构造方法) self.name = name #对象属性(普通字段)
self.__age = age # 私有对象属性(私有普通字段) def func1(self): # 普通方法
pass def __func(self): #私有方法
print(666) @classmethod # 类方法
def class_func(cls):
""" 定义类方法,至少有一个cls参数 """
print('类方法') @staticmethod #静态方法
def static_func():
""" 定义静态方法 ,无默认参数"""
print('静态方法') @property # 属性
def prop(self):
pass
1.2面向对象的私有和公有
对于静态字段(静态变量),普通字段(对象属性),方法
公有:类可以访问,类内部可以访问,派生类可以访问
私有:仅类内部可以访问
class C: name = "公有静态字段" def func(self):
print C.name class D(C): def show(self):
print C.name C.name # 类访问 obj = C()
obj.func() # 类内部可以访问 obj_son = D()
obj_son.show() # 派生类中可以访问
公有静态字段
class C: __name = "私有静态字段" def func(self):
print C.__name class D(C): def show(self):
print C.__name C.__name # 不可在外部访问 obj = C()
obj.__name # 不可在外部访问
obj.func() # 类内部可以访问 obj_son = D()
obj_son.show() #不可在派生类中可以访问
私有静态字段
class C: __name = "私有静态字段" def func(self):
print C.__name class D(C): def show(self):
print C.__name C.__name # 不可在外部访问 obj = C()
obj.__name # 不可在外部访问
obj.func() # 类内部可以访问 obj_son = D()
obj_son.show() #不可在派生类中可以访问
公有普通字段
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_son = D();
obj_son.show() # 派生类中访问 ==> 错误
私有普通字段
class C: def __init__(self):
pass def add(self):
print('in C') class D(C): def show(self):
print('in D') def func(self):
self.show()
obj = D()
obj.show() # 通过对象访问
obj.func() # 类内部访问
obj.add() # 派生类中访问
公有方法
class C: def __init__(self):
pass def __add(self):
print('in C') class D(C): def __show(self):
print('in D') def func(self):
self.__show()
obj = D()
obj.__show() # 通过不能对象访问
obj.func() # 类内部可以访问
obj.__add() # 派生类中不能访问
私有方法
1.3面向对象的成员
1 字段
class Province: # 静态字段
country = '中国' def __init__(self, name): # 普通字段
self.name = name # 直接访问普通字段
obj = Province('河北省')
print obj.name # 直接访问静态字段
Province.country
上面的代码可以看出:普通字段需要通过对象来访问 , 静态字段需要通过类访问
内存中存储方式:
静态字段在内存中子保存一份,实例化对象后,访问静态字段都指向类中的这个内存地址
普通字段在每个对象中都要保存一份
2方法
方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
- 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
- 类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
- 静态方法:由类调用;无默认参数;
class Foo: def __init__(self, name):
self.name = name def ord_func(self):
""" 定义普通方法,至少有一个self参数 """ # print self.name
print '普通方法' @classmethod
def class_func(cls):
""" 定义类方法,至少有一个cls参数 """
return cls('xingchen') @staticmethod
def static_func(): #设置不依赖于类和函数,不需要它们传self或者cls
""" 定义静态方法 ,无默认参数""" print '静态方法'
@staticmethod
def static_func2(n): #可以设置为传递一个参数
print('n') # 调用普通方法
f = Foo()
f.ord_func() # 调用类方法
Foo.class_func()
Foo.name #可以打印出xingchen # 调用静态方法
Foo.static_func() f.static_func2(1)
Foo.static_func2(2)
相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。
不同点:方法调用者不同、调用方法时自动传入的参数不同。
3属性
什么是property
它是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
class People:
def __init__(self,name,weight,height):
self.name=name
self.weight=weight
self.height=height
@property
def bmi(self):
return self.weight / (self.height**2) p1=People('egon',75,1.85)
print(p1.bmi) #本来应该时p1.bmi()
为什么要用property
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则
由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
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.deltter
def price(self, value):
del self.original_price obj = Goods()
obj.price # 获取商品价格
obj.price = 200 # 修改商品原价
del obj.price # 删除商品原价
二面向对象的内置函数
1 isinstance和issubclass
isinstance() 与 type() 区别:
type() 不会认为子类是一种父类类型,不考虑继承关系。
isinstance() 会认为子类是一种父类类型,考虑继承关系。
#isinstance(obj,cls)检查是否obj是否是类 cls 的对象
class A:pass
class B(A):pass abj=B()
print(isinstance(abj,B)) #True
print(isinstance(abj,A)) #True #issubclass(sub, super)检查sub类是否是 super 类的派生类
print(issubclass(B,A)) #True
2 反射
反射:是通过字符串的形式去操作对象相关的属性
I对实例化对象的反射
class Foo:
f='类的静态变量'
def __init__(self,name,age):
self.name=name
self.age=age
def say_hi(self):
print('my name is: ',self.name) obj=Foo('xincheng',18)
print(obj.name) #xincheng
print(hasattr(obj,'name')) #True 检查是否含有name的属性
#获取
my_name=getattr(obj,'name') #获取某个对象的属性
print(my_name) #xincheng
func=getattr(obj,'say_hi') #获取某个对象的属性
func() #my name is: xincheng
#报错设置
# print(getattr(obj,'aa')) #报错:AttributeError: 'Foo' object has no attribute 'aa'
print(getattr(obj,'aa','没有此属性')) #可以设置自己需要的报错说明 没有此属性
#增加或修改
setattr(obj,'sb','hehe')
print(obj.__dict__) #{'name': 'xincheng', 'age': 73, 'sb': 'hehe'}
print(obj.sb) #hehe
setattr(obj,'show_name',lambda self:self.name+'sb') #此属性相当于设置了一个函数
print(obj.__dict__) #{'name': 'xincheng', 'age': 73, 'sb': 'hehe', 'show_name': <function <lambda> at 0x0000027089CA6048>}
print(obj.show_name(obj)) #xinchengsb
#删除
delattr(obj,'age')
delattr(obj,'show_name')
delattr(obj,'show') #没有此属性报错,不能设置报错说明
II对类的反射
class Foo(object):
staticField = "old boy" def __init__(self):
self.name = 'wupeiqi' def func(self):
return 'func' @staticmethod
def bar():
return 'bar' print(getattr(Foo, 'staticField'))
print(getattr(Foo, 'func'))
print(getattr(Foo, 'bar'))
#结果为:
# old boy
# <function Foo.func at 0x000002903EE65730>
# <function Foo.bar at 0x000002903EE657B8>
func=getattr(Foo,'bar')
print(func) ## <function Foo.bar at 0x000002903EE657B8> 内存地址和类的bar方法一样
III对当前模块
def login():
print(888) msg=input('>>>>').strip()
import sys
print(sys.modules)
this_module=sys.modules[__name__]
print(this_module) #<module '__main__' from 'G:/day8/练习.py'> print(hasattr(this_module,'login')) #True
if hasattr(this_module,msg):
getattr(this_module,msg)()
else:
print('没有此属性')
IIII对另外一个模块
#模块名称模块测试反射,内容如下
def test():
print('来自于另外一个模块') #本地操作:
import 模块测试反射 as obj
print(hasattr(obj,'test'))
getattr(obj,'test')()
3 __len__
class A:
def __init__(self):
self.a = 1
self.b = 2 def __len__(self):
return len(self.__dict__)
a = A()
print(a.__dict__) #{'a': 1, 'b': 2}
print(len(a)) #2 使用len函数的时候它计算的是实例化对象字典的长度
4 __hash__
class A:
def __init__(self):
self.a = 1
self.b = 2 def __hash__(self):
return hash(str(self.a)+str(self.b))
a = A()
print(hash(a)) #这个hash值刷新一次改变一次
5 __str__和__repr__
如果一个类定义了__str__方法,那么在打印的时候,默认触发该方法
format_dict={
'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
}
class School:
def __init__(self,name,addr,type):
self.name=name
self.addr=addr
self.type=type def __repr__(self):
return 'School(%s,%s)' %(self.name,self.addr)
def __str__(self):
return '(%s,%s)' %(self.name,self.addr) def __format__(self, format_spec):
if not format_spec or format_spec not in format_dict:
format_spec='nat'
fmt=format_dict[format_spec]
return fmt.format(obj=self) s1=School('oldboy1','北京','私立')
print('from repr: ',repr(s1)) #from repr: School(oldboy1,北京)
print('from str: ',str(s1)) #from str: (oldboy1,北京)
print(s1) #(oldboy1,北京) 默认触发str方法 '''
str函数或者print函数--->obj.__str__()
repr或者交互式解释器--->obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
注意:这俩方法的返回值必须是字符串,否则抛出异常
''' print(format(s1,'nat'))
print(format(s1,'tna'))
print(format(s1,'tan'))
print(format(s1,'asfdasdffd'))
#结果为:
# oldboy1-北京-私立
# 私立:oldboy1:北京
# 私立/北京/oldboy1
# oldboy1-北京-私立
打印类型的触发
class B: def __str__(self):
return 'str : class B' def __repr__(self):
return 'repr : class B' b = B()
print('%s' % b) #str : class B
print('%r' % b) #repr : class B
6 __call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: def __init__(self):
pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__
obj() # 执行 __call__ #打印出 __call__
7 __del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo:
def __del__(self):
print('del----->') obj=Foo()
print('hehe!')
'''
结果为:
hehe!
del----->
这种情况是等待这个py的脚本完成执行的时候,触发del命令
'''
#如果换一种情况呢
class Moo:
def __del__(self):
print('del----->') oby=Moo()
del oby #提前触发 del命令
print('hehe!')
'''
结果为:
del----->
hehe! '''
8 __new__
此方法在实例化的时候触发,它的调用在__init__之前发生,object默认就有此方法
先讲一个模式:单例模式 --》就是一个类只能有一个实例
应用场景
1.当一个类,多次实例化时,每个实例都会占用资源,而且实例初始化会影响性能,这个时候就可以考虑使用单例模式,它给我们带来的好处是只有一个实例占用资源,并且只需初始化一次
2.当有同步需要的时候,可以通过一个实例来进行同步控制,比如对某个共享文件(如日志文件)的控制,对计数器的同步控制等,这种情况下由于只有一个实例,所以不用担心同步问题
情况一:一般的情况
class A:
def __init__(self):
self.x = 1
print('in init function')
def __new__(cls, *args, **kwargs):
print('in new function')
return object.__new__(A, *args, **kwargs) a = A()
'''
in new function #触发__new__,在__init__之前
in init function
'''
print(a.x) # b=A() # 结果和a一样
情况二:单例模式
class B:
__instance = None def __new__(cls, *args, **kwargs):
if cls.__instance is None:
obj = object.__new__(cls)
cls.__instance = obj
return cls.__instance def __init__(self, name, age):
self.name = name
self.age = age def func(self):
print(self.name) a = B('alex', 80) # 实例化,传值
print(a.name)
b = B('egon', 20) # 实例化,覆盖值
print(a)
print(b)
print(a.name)
print(b.name)
'''
alex
<__main__.B object at 0x0000023A1D0B8BA8>
<__main__.B object at 0x0000023A1D0B8BA8>
egon
egon
它们内存地址一样,这是个单例模式的例子
b实例化的时候,传的值覆盖了a
'''
单例模式
9 __eq__
使用==的时候触发
10 item系列
class Foo:
def __init__(self,name):
self.name=name def __getitem__(self, item):
print('getitem----->')
return self.__dict__[item] def __setitem__(self, key, value):
print('setitem----->')
self.__dict__[key]=value
def __delitem__(self, key):
print('del obj[key]时,我执行')
self.__dict__.pop(key)
def __delattr__(self, item):
print('del obj.key时,我执行')
self.__dict__.pop(item) f1=Foo('sb')
print(f1['name']) #触发 getitem方法
f1['age']=18 #触发setitem方法
f1['age1']=19 #触发setitem方法
del f1.age1 #触发 delattr方法
del f1['age'] #触发 delitem方法
f1['name']='alex' #触发setitem方法
# print(f1.__dict__) '''
执行结果为:
getitem----->
sb
setitem----->
setitem----->
del obj.key时,我执行
del obj[key]时,我执行
setitem----->
{'name': 'alex'}
'''
11 最后来看一个实例,关于hash和eq
class Person:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex def __hash__(self):
return hash(self.name+self.sex) def __eq__(self, other):
if self.name == other.name and self.sex == other.sex:return True p_lst = []
for i in range(10):
p_lst.append(Person('egon',i,'male')) print(p_lst)
yy=set(p_lst)
print(yy)
'''
结果为:
[<__main__.Person object at 0x00000152982D8DD8>, <__main__.Person object at 0x00000152982D8E10>, <__main__.Person object at 0x00000152982D8EB8>, <__main__.Person object at 0x00000152982E1EB8>, <__main__.Person object at 0x00000152982E1E80>,\
<__main__.Person object at 0x00000152984770F0>, <__main__.Person object at 0x00000152984774E0>, <__main__.Person object at 0x0000015298477518>,<__main__.Person object at 0x0000015298477550>, <__main__.Person object at 0x0000015298477588>]
{<__main__.Person object at 0x00000152982D8DD8>} '''
通过debug模式调试看到过程:针对set(p_lst)
1 集合是个去重的过程,判断一个元素是否是重复的看的是hash值
2 调用hash值就触发了__hash__,找到元素的hash值
首先<__main__.Person object at 0x00000152982D8DD8>开始放入集合中,接着<__main__.Person object at 0x00000152982D8E10>也触发__hash__放入集合中
3 两个元素的比较接着触发了 __eq__ ,而eq设置的判断标准,它们几乎一样,返回true ,也就是这两个元素的hash判断标准而言,它们是相等的,这样的话,元素<__main__.Person object at 0x00000152982D8E10>被去除了
4 以此类推,接着下一个元素
5 最后只会剩下唯一的第一个元素
day7--面向对象进阶(内含反射和item系列)的更多相关文章
- 铁乐学python_day23_面向对象进阶1_反射
铁乐学python_day23_面向对象进阶1_反射 以下内容大部分摘自博客http://www.cnblogs.com/Eva-J/ isinstance()和issubclass() 两者的返回值 ...
- 面向对象 反射 和item系列和内置函数和__getattr__和__setattr__
反射 反射主要用在网络编程中, python面向对象的反射:通过字符串的形式操作对象相关的属性.python的一切事物都是对象. 反射就是通过字符串的形式,导入模块:通过字符串的形式,去模块寻找指定函 ...
- python开发面向对象进阶:反射&内置函数
isinstance和issubclass isinstance(obj,cls)检查是否obj是否是类 cls 的对象或者子类的对象 class Foo(object): pass class ba ...
- python ——面向对象进阶(反射,双下线方法,静态方法,类方法)
属性 如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种. 哎,其实就是这样,我们看一下当我们想查看税后工资的时候,这其实是一个人的属性,但是它却 ...
- [ python ] 反射及item系列
反射 什么是反射? 通过字符串的形式操作对象相关属性.python中的事物都是对象: 关键方法: (1)getattr:获取属性 (2)setattr:设置属性 (3)hashattr:检测是否含有属 ...
- day7 面向对象进阶
面向对象高级语法部分 通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例 ...
- day7面向对象--进阶
静态方法(@staticmethod) 通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里 ...
- python面向对象( item系列,__enter__ 和__exit__,__call__方法,元类)
python面向对象进阶(下) item系列 __slots__方法 __next__ 和 __iter__实现迭代器 析构函数 上下文管理协议 元类一.item系列 把对象操作属性模拟成字典的 ...
- 面向对象的进阶(item系列,__new__,__hash__,__eq__)
面向对象的进阶(item系列,__new__,__hash__,__eq__) 一.item系列 getitem.setitem.delitem(操作过程达到的结果其实就是增删改查) class ...
随机推荐
- 大数据离线分析平台 JSSDK数据收集引擎编写
JsSDK设计规则在js sdk中我们需要收集launch.pageview.chargeRequest和eventDuration四种数据,所以我们需要在js中写入四个方法来分别收集这些数据,另外我 ...
- Java MyBatis insert数据库数据后返回主键
<selectKey keyProperty="id" resultType="java.lang.Long" order="AFTER&quo ...
- table 设置每列的颜色
ISBN Title Price 3476896 My first HTML $53 5869207 My first CSS $49 <!DOCTYPE html> <html ...
- 蓝桥杯-四阶幻方(DFS)
标题:四阶幻方 把1~16的数字填入4x4的方格中,使得行.列以及两个对角线的和都相等,满足这样的特征时称为:四阶幻方. 四阶幻方可能有很多方案.如果固定左上角为1,请计算一共有多少种方案. 比如: ...
- 峰Redis学习(1)Redis简介和安装
是从博客:http://blog.java1234.com/blog/articles/310.html参考过来的: 第一节:Redis 简介 为什么需要NoSQL,主要应对以下问题,传统关系型数据库 ...
- PAT 乙级 1027 打印沙漏(20) C++版
1027. 打印沙漏(20) 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 本题要求你写个程序把给定的符号打印成 ...
- python中画散点图
python中画散点图 示例代码: import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d impor ...
- 云中树莓派(2):将传感器数据上传到 AWS IoT 并利用Kibana进行展示
云中树莓派(1):环境准备 云中树莓派(2):将传感器数据上传到AWS IoT 并利用Kibana进行展示 1. 传感器安装及配置 1.1 DHT22 安装 DHT22 是一款温度与湿度传感器,它有3 ...
- 学习笔记之Sublime Text
Sublime Text - A sophisticated text editor for code, markup and prose https://www.sublimetext.com/ A ...
- java为什么匿名内部类的参数引用时final(转)
https://blog.csdn.net/z69183787/article/details/68490440 https://www.zhihu.com/question/21395848 htt ...