一面向对象的结构和成员

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系列)的更多相关文章

  1. 铁乐学python_day23_面向对象进阶1_反射

    铁乐学python_day23_面向对象进阶1_反射 以下内容大部分摘自博客http://www.cnblogs.com/Eva-J/ isinstance()和issubclass() 两者的返回值 ...

  2. 面向对象 反射 和item系列和内置函数和__getattr__和__setattr__

    反射 反射主要用在网络编程中, python面向对象的反射:通过字符串的形式操作对象相关的属性.python的一切事物都是对象. 反射就是通过字符串的形式,导入模块:通过字符串的形式,去模块寻找指定函 ...

  3. python开发面向对象进阶:反射&内置函数

    isinstance和issubclass isinstance(obj,cls)检查是否obj是否是类 cls 的对象或者子类的对象 class Foo(object): pass class ba ...

  4. python ——面向对象进阶(反射,双下线方法,静态方法,类方法)

    属性 如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种. 哎,其实就是这样,我们看一下当我们想查看税后工资的时候,这其实是一个人的属性,但是它却 ...

  5. [ python ] 反射及item系列

    反射 什么是反射? 通过字符串的形式操作对象相关属性.python中的事物都是对象: 关键方法: (1)getattr:获取属性 (2)setattr:设置属性 (3)hashattr:检测是否含有属 ...

  6. day7 面向对象进阶

    面向对象高级语法部分 通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例 ...

  7. day7面向对象--进阶

    静态方法(@staticmethod)     通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里 ...

  8. python面向对象( item系列,__enter__ 和__exit__,__call__方法,元类)

    python面向对象进阶(下)   item系列 __slots__方法 __next__ 和 __iter__实现迭代器  析构函数 上下文管理协议 元类一.item系列 把对象操作属性模拟成字典的 ...

  9. 面向对象的进阶(item系列,__new__,__hash__,__eq__)

      面向对象的进阶(item系列,__new__,__hash__,__eq__) 一.item系列 getitem.setitem.delitem(操作过程达到的结果其实就是增删改查) class ...

随机推荐

  1. kafka重复数据问题排查记录

    问题 向kafka写数据,然后读kafka数据,生产的数据量和消费的数据量对不上. 开始怀疑人生,以前奠定的基础受到挑战... 原来的测试为什么没有覆盖生产量和消费量的对比? 消费者写的有问题?反复检 ...

  2. 黄聪: bootstrap 多模态框实现

    默认情况下,bootstrap模态框是不支持多个覆盖的,下面是一个解决办法(本人亲测), 将下面的代码复制到当前需要多个模态框的页面,问题就可以解决 $(document).on('show.bs.m ...

  3. bzoj4933: 妙

    Description Mr.董已经成长为一个地区的领袖,真是妙啊.董所在的地区由n个小区域构成,这些小区域构成了一棵树,每个小 区域都有一个重要程度,一个连通块的重要程度为其包含的小区域重要程度之和 ...

  4. PAT 甲级 1011 World Cup Betting (20)(20 分)

    1011 World Cup Betting (20)(20 分)提问 With the 2010 FIFA World Cup running, football fans the world ov ...

  5. [UE4]Size To content自动适配大小

  6. switch case 变量初始化问题

    今天再写alsa的时候遇到一个稀奇古怪的问题,网上看了下资料,摘出来入下 代码: int main() { ; switch(a) { : ; break; : break; default: bre ...

  7. 如何查看yum 安装的软件路径

    1.首先安装一个redis [root@iZbp1eem925ojwyx17ao9kZ ~]# yum install redis 2.查找redis的安装包 [root@iZbp1eem925ojw ...

  8. MySQL之 Mysqldump导出数据库

    参数大全 参数说明 --all-databases , -A 导出全部数据库. mysqldump -uroot -p --all-databases --all-tablespaces , -Y 导 ...

  9. Hibernate 抓取策略

    抓取策略: 为了改变SQL语句执行的方式 当应用程序需要在Hibernate实体对象的关联关系间进行导航的时候,Hibernate如何获取关联对象的策略 抓取策略可以在O/R映射的元数据中声明,也可以 ...

  10. iOS 懒加载 字典转模型

    >>>懒加载 一.介绍 懒加载又称延时加载,即在系统调用时加载,如果系统不调用则不会加载,所谓懒加载其实就是重写其get方法. 在使用懒加载时要先判断该方法是否存在,如果不存在再进行 ...