python之面向对象进阶

Posted xiaobin12126

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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方法
纸牌实例

 

以上是关于python之面向对象进阶的主要内容,如果未能解决你的问题,请参考以下文章

python进阶之面向对象初识

Python之面向对象进阶

进阶学Python:Python面向对象之属性方法

Python进阶(十六)----面向对象之~封装,多态,鸭子模型,super原理(单继承原理,多继承原理)

python-面向对象进阶

Python基础之面向对象进阶