python之面向对象进阶

1 # 2 == 3   # 值是否相等
2 # 2 is 3   # 内存地址是否相等

isinstance和issubclass

isinstance(obj,cls)检查是否obj是否是类 cls 的对象 判断第一个参数是否是第二个参数的实例

1 class A:pass
2 class B(A):pass
3 class C(B):pass
4 c = C()
5 print(isinstance(c,A))   # 包含继承关系的判断 #true

issubclass(sub, super)检查sub类是否是 super 类的派生类 第一个参数是疑似子类,第二个参数是疑似父类.

1 class A:pass
2 class B(A):pass
3 print(issubclass(A,B))  #false
4 print(issubclass(B,A))  #true

反射

1 什么是反射

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

四个可以实现自省的函数

下列方法适用于类和对象(一切皆对象,类本身也是一个对象)

1 # hasattr  判断某一个 变量 是否能够.调用一个名字,返回True或者False
2 # getattr  直接获取一个变量中的名字的值
3 
4 class A:
5     name = 'alex'   # 静态 属性
6     age = 83        # 静态 属性
7 print(getattr(A,'name')) #alex
8 print(hasattr(A,'name')) #true
hasattr,getattr
 1 class Student:
 2     def __init__(self,name,age):
 3         self.name = name
 4         self.age = age
 5     def show(self):
 6         for key in self.__dict__:
 7             print(key,self.__dict__[key])
 8 
 9 yuan = Student('苑昊',38)
10 if hasattr(yuan,'name'):
11     print(getattr(yuan,'name')) #苑昊
12 if hasattr(yuan,'show'):
13     func = getattr(yuan,'show')
14     func()   #name 苑昊 age 38
例子二
 1 # setattr  为一个变量增加或者修改一个属性
 2 # delattr  删除一个变量中的属性或者方法
 3 
 4 class Student:
 5     def __init__(self,name,age):
 6         self.name = name
 7         self.age = age
 8     def show(self):
 9         for key in self.__dict__:
10             print(key,self.__dict__[key])
11 
12 hei = Student('小黑',18)
13 hei.sex = '不详'
14 print(hei.sex) #不详
15 setattr(hei,'sex','不详')  # 增改操作
16 print(hei.sex) #不详
17 setattr(hei,'sex','male')
18 print(hei.sex) #不详
19 delattr(hei,'sex')    # 删除操作
20 print(hei.__dict__)
21 def wahaha(a,b):   # 专属于某一个对象的静态方法
22     print(a,b) #{'name': '小黑', 'age': 18}
setattr,delattr
 1 # 反射类中的名字
 2 # getattr(类名,'静态属性')
 3 # getattr(类名,'类方法')()
 4 # getattr(类名,'静态方法')()
 5 
 6 # 反射对象中的名字
 7 # getattr(对象名,'对象属性')
 8 # getattr(对象名,'方法名')()
 9 
10 # 反射模块中的名字
11 # import 模块名
12 # getattr(模块名,'模块中的变量')
13 # getattr(模块名,'模块中的函数')()
14 # getattr(模块名,'模块中的类名')
15 
16 # 反射当前模块中的名字
17 # import sys
18 # getattr(sys.modules[__name__],'变量')
19 # getattr(sys.modules[__name__],'函数')()
20 # getattr(sys.modules[__name__],'类名')
21 
22 # sys.modules[__name__]
23 # import sys
24 # print(sys.modules[__name__])  # 所有导入过的模块
25 # {'字符串数据类型的模块名':模块的内存地址}
26 # {'__main__':当前模块的内存地址}
View Code
1 class  person:pass
2 hei = person()
3 setattr(hei,'name','小黑')
4 setattr(hei,'age',18)
5 print(hei,hei.__dict__)
反射的知识
 1 # 怎么反射类 ?
 2 # class Student:
 3 #     def __init__(self,name,age):
 4 #         self.name = name
 5 #         self.age = age
 6 #     def show_student(self):
 7 #         for key in self.__dict__:
 8 #             print(key,self.__dict__[key])
 9 #
10 # class Teacher:
11 #     def __init__(self, name, age):
12 #         self.name = name
13 #         self.age = age
14 #
15 #     def show_teacher(self):
16 #         for key in self.__dict__:
17 #             print(key, self.__dict__[key])
18 #
19 # class Manager:
20 #     def __init__(self, name, age):
21 #         self.name = name
22 #         self.age = age
23 #
24 #     def show_manager(self):
25 #         for key in self.__dict__:
26 #             print(key, self.__dict__[key])
27 # hei = Student('小黑',18)
28 # import sys
29 # main = sys.modules[__name__]
30 # import my_moudle
31 # cls = getattr(my_moudle,'Student')
32 # hei = cls('小黑',18)
33 # print(hei,hei.__dict__)
34 
35 # 'Manager' 'Teacher' 'Student'
36 # 获取字符串数据类型的类名
37 # cls_name = input('>>>')
38 
39 # 根据输入反射找到具体的类
40 # if hasattr(main,cls_name):
41 #     cls = getattr(main,cls_name)
42 
43 # 实例化对象
44 # alex = cls('alex',81)
45 # print(type(alex))
46 # 展示这个对象中的所有方法
47 # for i in alex.__dict__:
48 #     print(i,alex.__dict__[i])
反射二

__str__和__repr__

改变对象的字符串显示__str__,__repr__

自定制格式化字符串__format__

 1 #_*_coding:utf-8_*_
 2 
 3 format_dict={
 4     'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
 5     'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
 6     'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
 7 }
 8 class School:
 9     def __init__(self,name,addr,type):
10         self.name=name
11         self.addr=addr
12         self.type=type
13 
14     def __repr__(self):
15         return 'School(%s,%s)' %(self.name,self.addr)
16     def __str__(self):
17         return '(%s,%s)' %(self.name,self.addr)
18 
19     def __format__(self, format_spec):
20         # if format_spec
21         if not format_spec or format_spec not in format_dict:
22             format_spec='nat'
23         fmt=format_dict[format_spec]
24         return fmt.format(obj=self)
25 
26 s1=School('oldboy1','北京','私立')
27 print('from repr: ',repr(s1))
28 print('from str: ',str(s1))
29 print(s1)
30 
31 '''
32 str函数或者print函数--->obj.__str__()
33 repr或者交互式解释器--->obj.__repr__()
34 如果__str__没有被定义,那么就会使用__repr__来代替输出
35 注意:这俩方法的返回值必须是字符串,否则抛出异常
36 '''
37 print(format(s1,'nat'))
38 print(format(s1,'tna'))
39 print(format(s1,'tan'))
40 print(format(s1,'asfdasdffd'))
View Code
 1 class B:
 2 
 3      def __str__(self):
 4          return 'str : class B'
 5 
 6      def __repr__(self):
 7          return 'repr : class B'
 8 
 9 
10 b=B()
11 print('%s'%b)
12 print('%r'%b)
%s和%r

__del__

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

 1 import time
 2 class A:
 3     def __init__(self):
 4         self.f = open('userinfo','a')
 5     def consume(self):
 6         pass
 7     def __del__(self):
 8         '''在删除一个对象之前做一些收尾工作'''
 9         self.f.close()
10         print('删除一个对象的时候调用我')
11 
12 a = A()
13 time.sleep(1)
14 del a
15 # 删除一个对象的时候,如果内部存在__del__方法,
16 # 那么在删除一个对象之前先执行__del__方法中的代码
17 print(a) #  报错 name 'a' is not defined
View Code

item系列

__getitem__\__setitem__\__delitem__

 1 class A:
 2     def __init__(self,name):
 3         self.name = name
 4         self.age = 81
 5     def __getitem__(self, item):
 6         return self.__dict__[item]
 7     def __setitem__(self, key, value):
 8         self.__dict__[key] = value
 9     def __delitem__(self, key):
10         del self.__dict__[key]
11 a = A('alex')
12 print(a['name'])  # 对应了类中一个方法的语法 #alex
13 a.name
14 print(a['age'])  # 对应了类中一个方法的语法 #81
15 a.age
16 # 增加 和 修改一个属性
17 a['sex'] = '不详'
18 a.sex = '不详'
19 print(a.__dict__)  #{'name': 'alex', 'age': 81, 'sex': '不详'}
20 print(a.sex)  #不详
21 print(a['sex']) #不详
22 a['sex'] = ''
23 print(a.__dict__) #'{'name': 'alex', 'age': 81, 'sex': '女'}
24 del a['sex']
25 print(a.__dict__) #'name': 'alex', 'age': 81}
View Code

__new__

 1 # 元类
 2 # 有一个元类 在创建类
 3 # type()  所有直接用class创建出来的类的元类都是type
 4 
 5 # class 类名(B,classMeta = 元类名)
 6 # class 类名(B,classMeta = type)  # 默认
 7 
 8 # 元类 创造 类     所以所有的类的type都是它的元类,默认是type
 9 # 类   创造 对象   具体创造对象的方法 __new__方法,所有的对象的type都是它对应的类
10 
11 # python中 一切皆对象
12 # 变量 都有它属于的数据类型
 1 class A:
 2     def __init__(self):
 3         print('执行init方法了')
 4     def __new__(cls):
 5         print('执行new方法了')
 6         return object.__new__(cls)   # 创造对象,将对象返回
 7 
 8 a = A()
 9 print(type(a))
10 # 执行new方法了
11 # 执行init方法了
12 # <class '__main__.A'>
13 print(type(A))
14 # 执行new方法了
15 # 执行init方法了
16 # <class 'type'>
17 
18 # 先执行__new__方法 创造出一个对象
19 # 然后把创造出来的对象传递给__init__方法
20 # 会把self自动的返回,被a接收
View Code
 1 # 一个类 可以被多次实例化 但是同一时间在python的内存中,只能有一个实例
 2 class A:
 3     _instance = None
 4     def __init__(self,name):
 5         '''给娃穿衣服'''
 6         self.name = name
 7     def __new__(cls, *args, **kwargs):
 8         '''生娃的过程'''
 9         if not A._instance:
10             A._instance = object.__new__(cls)
11         return A._instance
12 a1 = A('alex')  # 第一次实例化的时候创造一个实例
13 print(a1.name)
14 a2 = A('egon')
15 print(a1.name,a2.name)  # 'alex' 'alex'
单例模式

__call__

对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

1 class A:
2     def __call__(self,a):
3         print('执行我了',a)
4     def call(self,a):
5         print('执行我了',a)
6 a = A()
7 a('abc')   # __call__   #执行我了 abc
8 a.call('aaa') #执行我了 aaa
View Code

__len__

1 def len(obj):
2     return obj.__len__()
3 print(len(hei))  #4
View Code

__eq__

 1 class A:
 2     def __init__(self,name,cls,age,sex):
 3         self.name = name
 4         self.cls = cls
 5         self.age = age
 6         self.sex = sex
 7     def __eq__(self, other):
 8         # if self.__dict__ == other.__dict__:return True
 9         return True
10     def __len__(self):
11         return len(self.__dict__)
12 
13 hei = A('小黑','py10期',18,'')
14 hei2 = A('小2黑','py11期',17,'')
15 print(hei.__dict__) #{'name': '小黑', 'cls': 'py10期', 'age': 18, 'sex': '无'}
16 print(hei2.__dict__) #'name': '小2黑', 'cls': 'py11期', 'age': 17, 'sex': '无'}
17 print(hei == hei2)  #True
18 # 两个对象就算值是完全相等的,但是仍然内存地址不同
19 # == 实际上是比较内存地址的
20 # == 实际上是调用了__eq__方法
View Code

__hash__

# hash(obj)函数,obj对象对应的类必然内部实现了__hash__方法
# hash的结果就是__hash__方法的返回值
# 且在一次成的执行过程中是不会发生变化的
# 且要想作为字典的key或者作为集合的元素,这个对象对应的类必须实现__hash__方法
1 # 不可变的数据类型都可以被hash
2 class A:pass
3     # def __hash__(self):
4     #     return 1
5 a = A()
6 b = A()
7 
8 print(hash(a))   # object.__hash__()
9 print(hash(b))   # object.__hash__()
View Code

__format__

 1 #_*_coding:utf-8_*_
 2 
 3 format_dict={
 4     'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
 5     'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
 6     'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
 7 }
 8 class School:
 9     def __init__(self,name,addr,type):
10         self.name=name
11         self.addr=addr
12         self.type=type
13 
14     def __format__(self, format_spec):
15         return format_spec.format(obj=self)
16 
17 s1=School('oldboy1','北京','私立')
18 print(format(s1,format_dict['tna'])) #私立:oldboy1:北京
19 print(format(s1,format_dict['nat'])) #oldboy1-北京-私立
20 print(format(s1,format_dict['tan'])) #私立/北京/oldboy1
21 print(format(s1,'tna')) #tna
22 print(format(s1,'tan')) #tan
View Code

面试题

 1 # 有一个类,对应这个类产生了100个对象
 2 # 每个对象有三个属性 : 姓名 年龄 性别
 3 # 请对这一百个对象进行去重,如果姓名和性别相同,即便年龄不同也是相同的对象
 4 # 问最简便的方法?
 5 class Person:
 6     def __init__(self,name,age,sex):
 7         self.name = name
 8         self.age = age
 9         self.sex = sex
10     def __hash__(self):
11         return hash('%s%s'%(self.name,self.sex))
12     def __eq__(self, other):
13         if self.name == other.name and  
14             self.sex == other.sex:
15             return True
16 
17 p_lst = []
18 for i in range(100):
19     p_lst.append(Person('egon',i,'male'))
20 p_lst.append(Person('alex',i,'male'))
21 p_lst.append(Person('yuan',i,'male'))
22 print(p_lst)
23 print(set(p_lst)) # 报错不可hash 完成了__hash__
24 '''
25 # hash是否相等   __hash__
26 # 值是否相等     __eq__
27 
28 # 收获1
29 # 对于一些python当中已经存在的内置函数 内置数据类型 内置模块中的方法
30 # 都有可能依赖于类中的内置方法
31 # 收获2
32 # set方法依赖集合中元素对象的__hash__ __eq__
33 '''
金融公司
 1 from collections import namedtuple
 2 card = namedtuple('card',['num','col'])
 3 class A:
 4     num = [str(n) for n in range(2,11) ]+ list('jqka')
 5     col = ['红心','方板','梅花','黑桃']
 6     def __init__(self):
 7         self._cards = [card(num,col) for num in A.num
 8                       for col in A.col]
 9     def __len__(self):
10         return  len(self._cards)
11     def __getitem__(self, item):
12         return self._cards[item]
13     def __setitem__(self, key, value):
14         self._cards[key] = value
15 deck = A()
16 print('**', deck[:]) #打印所有的纸牌
17 from random import choice
18 print(choice(deck)) #打印随机的纸牌 
19 # deck对象对应的类中的getitem方法和len方法
纸牌实例
原文地址:https://www.cnblogs.com/xiaobin12126/p/9383167.html