• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

索静丨LLH

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

python学习——面对对象进阶

一、isinstance和issubclass

  isinstance(obj,cls)检查是否obj是否是类 cls 的对象

 1 class Foo:
 2     pass
 3 
 4 a = Foo()
 5 print(isinstance(Foo,object))
 6 
 7 # 输出:True
 8 
 9 class Parent(object):
10     pass
11 
12 b = Parent()
13 print(isinstance(Parent,object))
14 
15 # 输出:True

  由此可以看出,python3中若没有说明继承的是哪个类的时候,默认继承object。

  issubclass(sub, super)检查sub类是否是 super 类的派生类 

class Parent():
    pass

class Son(Parent):
    pass

print(issubclass(Parent,object))
print(issubclass(Son,Parent))

# 输出:
True
True

二、反射

  1、什么是反射(非常强大,也很重要)

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

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

    四个可以实现自省的函数

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

1 def hasattr(*args, **kwargs): # real signature unknown
2     """
3     Return whether the object has an attribute with the given name.
4     
5     This is done by calling getattr(obj, name) and catching AttributeError.
6     """
7     pass
hasattr
1 def getattr(object, name, default=None): # known special case of getattr
2     """
3     getattr(object, name[, default]) -> value
4     
5     Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
6     When a default argument is given, it is returned when the attribute doesn't
7     exist; without it, an exception is raised in that case.
8     """
9     pass
getattr
1 def setattr(x, y, v): # real signature unknown; restored from __doc__
2     """
3     Sets the named attribute on the given object to the specified value.
4     
5     setattr(x, 'y', v) is equivalent to ``x.y = v''
6     """
7     pass
setattr
1 def delattr(x, y): # real signature unknown; restored from __doc__
2     """
3     Deletes the named attribute from the given object.
4     
5     delattr(x, 'y') is equivalent to ``del x.y''
6     """
7     pass
delattr
 1 class Parent():
 2     p = '类的静态变量'
 3     def __init__(self,name,age,sex):
 4         self.name = name
 5         self.age = age
 6         self.sex = sex
 7 
 8     def say_hello(self):
 9         return '{}say {}'.format(self.name,'hello')
10 
11 obj = Parent('周曾吕',88,'不详')
12 
13 # 检测是否含有某个属性
14 print(hasattr(obj,'name'))
15 print(hasattr(obj,'age'))
16 print(hasattr(obj,'sex'))
17 print(hasattr(obj,'say_hello'))
18 
19 # 输出:
20 True
21 True
22 True
23 True
24 
25 # 获取属性
26 n1 = getattr(obj,'name')
27 n2 = getattr(obj,'age')
28 n3 = getattr(obj,'sex')
29 
30 print(n1,n2,n3)
31 
32 # 输出:周曾吕 88 不详
33 
34 func = getattr(obj,'say_hello')
35 print(func)
36 
37 # 输出:
38 <bound method Parent.say_hello of <__main__.Parent object at 0x00000222F34B2CF8>>
39 
40 # print(getattr(obj,'aaaa','不存在'))  # 不存在 报错
41 
42 # 设置属性(赋值)
43 setattr(obj,'sb',True)
44 setattr(obj,'show_name',lambda self:self.name + 'sb')
45 print(obj.__dict__)
46 print(obj.show_name(obj))
47 
48 # 输出:
49 {'name': '周曾吕', 'age': 88, 'sex': '不详', 'sb': True, 'show_name': <function <lambda> at 0x00000222F34CD730>}
50 周曾吕sb
51 
52 # 删除属性
53 delattr(obj,'sex')
54 delattr(obj,'show_name')
55 delattr(obj,'sb')
56 # delattr(obj,'show_name_aaa')   # 不存在就报错
57 
58 print(obj.__dict__)
59 
60 # 输出:
61 {'name': '周曾吕', 'age': 88}
hasattr,getattr,setattr,delattr四个方法的演示

 

 1 class Foo:
 2 
 3     staticName = 'University Guiyang'
 4 
 5     def __init__(self):
 6         self.name = 'liulonghai'
 7 
 8     def func(self):
 9         return 'in func now '
10 
11     @staticmethod
12     def qqxing():
13         return 'qqxing'
14 
15 print(getattr(Foo,'staticName'))
16 print(getattr(Foo,'func'))
17 print(getattr(Foo,'qqxing'))
18 
19 ret1 = getattr(Foo,'func')
20 ret2 = getattr(Foo,'qqxing')
21 
22 print(ret1(Foo))
23 print(ret2())
24 
25 # 输出:
26 University Guiyang
27 <function Foo.func at 0x0000020D5570E8C8>
28 <function Foo.qqxing at 0x0000020D5570E950>
29 in func now 
30 qqxing
类也是对象

  注意:当调用类里面的普通方法时,要传一个类名作为参数,否则会报错。如上面的 ret2(Foo)

 1 import sys
 2 
 3 n1 = 'qqxing'
 4 def func1():
 5     return 'in func1 now'
 6 
 7 n2 = 'wahaha'
 8 def func2():
 9     return 'in func2 now'
10 
11 the_module = sys.modules[__name__]
12 
13 if hasattr(the_module,'func1'):
14     ret1 = getattr(the_module,'func1')
15     print(ret1())
16 if hasattr(the_module,'func2'):
17     ret2 = getattr(the_module,'func2')
18     print(ret2())
19 
20 print(getattr(the_module,'n1'))
21 print(getattr(the_module,'n2'))
22 
23 # 输出:
24 in func1 now
25 in func2 now
26 qqxing
27 wahaha
反射当前模块成员或者函数

  注意:不管是函数还是变量,反射的时候只能有一个变量,且变量必须是全局变量。

  导入其他模块,可以利用反射来运行该模块中存在的方法

 1 import 面向对象的三大特性
 2 
 3 if hasattr(面向对象的三大特性,'A'):
 4     ret1 = getattr(面向对象的三大特性,'A')
 5     print(ret1)
 6     print(ret1())
 7 
 8 # 输出:
 9 <class '面向对象的三大特性.A'>
10 China
导入其他模块,利用反射来运行该模块中成员

  注意,若导入的模块是一个类而不是函数,运行的时候可能会报错,他会说这个类的类名不可调用,是因为这个类中没有__call__这个方法,如果你加上之后就不会报错了,但是他返回的是一个内存地址,没有显示这个函数的结果(不管你怎么调用都不显示,而且不会报错,是不是懵逼了),其实是因为类中没有实现__repr__或者__str__这两个双下方法中的其中一个,你加上就可以了。。。

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

  自定制如下的格式化字符串__format__ 👇

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

 四、__del__

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

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

 1 class A:
 2     def __del__(self):
 3         print('执行我呗!')
 4 
 5 a = A()
 6 del a
 7 print('*******')
 8 
 9 # 输出:
10 执行我呗!
11 *******
__del__

五、item系列

  5.1、__getitem__ __setitem__ __delitem__

 1 class A:
 2     def __init__(self,name):
 3         self.name = name
 4 
 5     def __getitem__(self, item):
 6         return self.__dict__[item]
 7 
 8     def __setitem__(self, key, value):
 9         self.__dict__[key] = value
10 
11     def __delitem__(self, key):
12         print('*******del obj[key]时,执行我啦********')
13         self.__dict__.pop(key)
14 
15     def __delattr__(self, item):
16         print('del obj[key]时,执行我啦')
17         self.__dict__.pop(item)
18 
19 a = A('小周哥')
20 a['age1'] = 18
21 a['age2'] = 88
22 print(a.__dict__)
23 del a.age2
24 del a['age1']
25 a['name'] = '小伟哥'
26 print(a.__dict__)
27 
28 # 输出:
29 {'name': '小周哥', 'age1': 18, 'age2': 88}
30 del obj[key]时,执行我啦
31 *******del obj[key]时,执行我啦********
32 {'name': '小伟哥'}
__getitem__ __setitem__ __delitem__ __delattr__

六、__new__

 1 class A:
 2     def __init__(self):
 3         self.x = 1000000
 4         print('in init function now ')
 5 
 6     def __new__(cls, *args, **kwargs):
 7         print('in new function now ')
 8         return object.__new__(A,*args,**kwargs)
 9 
10 a = A()
11 print(a.x)
12 
13 # 输出:
14 in new function now
15 in init function now
16 1000000
__new__
 1 class Singleton:
 2     def __new__(cls, *args, **kwargs):
 3         if not hasattr(cls,'_instance'):
 4             cls._instance = object.__new__(cls,*args,**kwargs)
 5 
 6         return cls._instance
 7 
 8 one = Singleton()
 9 one.name = '刘龙海'
10 two = Singleton()
11 two.name = '刘永贵'
12 print(one.name)
13 # 刘永贵
14 print(id(one))
15 # 3237255572616
16 print(id(two))
17 # 3237255572616
18 print(one.name)
19 # 刘永贵
20 print(one == two)
21 # True
22 print(one is two)
23 # True
__nw__ 和 单例模式

   单例模式:在类中始终都只有一个实例。

 1 class A:
 2     def __new__(cls, *args, **kwargs):
 3         if not hasattr(cls,'_instance'):
 4             cls._instance = object.__new__(A,*args,**kwargs)
 5         return cls._instance
 6 
 7 a = A()
 8 aa = A()
 9 aa.name = '刘永贵'
10 a.name = '刘龙海'
11 print(a.name)
12 # 刘龙海
13 print(aa.name)
14 # 刘龙海
15 print(id(a))
16 # 2266637659216
17 print(id(aa))
18 # 2266637659216
19 print(a == aa)
20 # True
21 print(a is aa )
22 # True
傻傻分不清的 单例模式

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

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

 1 class A:
 2     def __init__(self):
 3         pass
 4 
 5     def __call__(self, *args, **kwargs):
 6         return 'in __call__'
 7 
 8 a = A()
 9 print(a())
10 print(A()())
11 
12 # 输出:
13 in __call__
14 in __call__
__call__

八、__len__

 1 class A:
 2     def __init__(self):
 3         self.a = 1
 4         self.aa = 2
 5 
 6     def __len__(self):
 7         return len(self.__dict__)
 8 
 9 aaa = A()
10 print(len(aaa))
11 
12 # 输出:2
__len__

九、__hash__

 1 class A:
 2     def __init__(self):
 3         self.a = 1
 4         self.aa = 2
 5 
 6     def __hash__(self):
 7         return hash(str(self.a)+str(hash(self.aa)))
 8 
 9 aaa = A()
10 print(hash(aaa))
11 
12 # 输出:5078281282522828503
__hash__

十、__eq__

 1 class A:
 2     def __init__(self):
 3         self.a = 1
 4         self.aa = 2
 5 
 6     def __eq__(self, other):
 7         if self.a == other.a and self.aa == other.aa:
 8             return True
 9 
10 c1 = A()
11 c2 = A()
12 print(c1 == c2)
13 
14 # 输出:True
__eq__
 1 class A:
 2     def __init__(self):
 3         self.a = 1
 4         self.aa = 2
 5 
 6     def __eq__(self, other):
 7         if self.a == other.a and self.aa == other.aa:
 8             return True
 9 
10 a = A()
11 aa = A()
12 print(a == aa)
13 
14 # 输出:True
__eq__ 1

十一、面向对象进阶实例
  1.扑克牌游戏

 1 from collections import namedtuple
 2 from random import choice,shuffle
 3 import json
 4 
 5 Card = namedtuple('牌',['num_types','numbers'])
 6 class Pukepai():
 7     numbers = [str(n) for n in range(2,11)] + list('JQKA')
 8     num_types = ['黑桃','红桃','梅花','方块']
 9 
10     def __init__(self):
11         self._cards = [Card(num_type,number) for num_type in Pukepai.num_types
12                                              for number in Pukepai.numbers]
13 
14     def __call__(self, *args, **kwargs):
15         return Pukepai
16 
17     def __len__(self):
18         return len(self._cards)
19 
20     def __getitem__(self, item):
21         return self._cards[item]
22 
23     def __setitem__(self, key, value):
24         self._cards[key] = value
25 
26     def __str__(self):
27         return json.dumps(self._cards,ensure_ascii=False)
28 
29 puke = Pukepai()
30 print(puke[10])
31 print(choice(puke))
32 print(choice(puke))
33 print(choice(puke))
34 print(choice(puke))
35 print(choice(puke))
36 shuffle(puke)
37 print(puke[:52])
38 
39 # 输出:
40 牌(num_types='黑桃', numbers='Q')
41 牌(num_types='方块', numbers='Q')
42 牌(num_types='方块', numbers='4')
43 牌(num_types='红桃', numbers='8')
44 牌(num_types='红桃', numbers='3')
45 牌(num_types='梅花', numbers='6')
46 [牌(num_types='红桃', numbers='J'), 牌(num_types='红桃', numbers='8'), 牌(num_types='方块', numbers='2'), 牌(num_types='黑桃', numbers='7'), 牌(num_types='红桃', numbers='2'), 牌(num_types='方块', numbers='A'), 牌(num_types='梅花', numbers='3'), 牌(num_types='方块', numbers='7'), 牌(num_types='梅花', numbers='8'), 牌(num_types='方块', numbers='K'), 牌(num_types='黑桃', numbers='Q'), 牌(num_types='方块', numbers='3'), 牌(num_types='红桃', numbers='7'), 牌(num_types='梅花', numbers='5'), 牌(num_types='方块', numbers='8'), 牌(num_types='红桃', numbers='A'), 牌(num_types='黑桃', numbers='J'), 牌(num_types='梅花', numbers='10'), 牌(num_types='黑桃', numbers='K'), 牌(num_types='红桃', numbers='10'), 牌(num_types='方块', numbers='4'), 牌(num_types='梅花', numbers='Q'), 牌(num_types='梅花', numbers='7'), 牌(num_types='黑桃', numbers='3'), 牌(num_types='方块', numbers='5'), 牌(num_types='红桃', numbers='4'), 牌(num_types='方块', numbers='10'), 牌(num_types='黑桃', numbers='4'), 牌(num_types='红桃', numbers='9'), 牌(num_types='梅花', numbers='4'), 牌(num_types='红桃', numbers='3'), 牌(num_types='黑桃', numbers='A'), 牌(num_types='梅花', numbers='K'), 牌(num_types='黑桃', numbers='8'), 牌(num_types='黑桃', numbers='5'), 牌(num_types='方块', numbers='J'), 牌(num_types='方块', numbers='Q'), 牌(num_types='红桃', numbers='6'), 牌(num_types='梅花', numbers='J'), 牌(num_types='黑桃', numbers='6'), 牌(num_types='梅花', numbers='2'), 牌(num_types='梅花', numbers='A'), 牌(num_types='黑桃', numbers='2'), 牌(num_types='梅花', numbers='9'), 牌(num_types='红桃', numbers='Q'), 牌(num_types='黑桃', numbers='9'), 牌(num_types='方块', numbers='9'), 牌(num_types='梅花', numbers='6'), 牌(num_types='黑桃', numbers='10'), 牌(num_types='红桃', numbers='K'), 牌(num_types='方块', numbers='6'), 牌(num_types='红桃', numbers='5')]
扑克牌游戏

  2.一道面试题

 1 class Person:
 2     def __init__(self,name,sex,age):
 3         self.name = name
 4         self.age = age
 5         self.sex = sex
 6 
 7     def __hash__(self):
 8         return hash(self.name + self.sex)
 9 
10     def __eq__(self, other):
11         if self.name == other.name and self.sex == other.sex:
12             return True
13 
14 p_lst = []
15 for i in range(10):
16     p_lst.append(Person('刘龙海','男',i))
17 
18 print(p_lst[:2])
19 print(set(p_lst))
20 
21 # 输出:
22 [<__main__.Person object at 0x0000023940FF5B38>, <__main__.Person object at 0x0000023940FF5C88>]
23 {<__main__.Person object at 0x0000023940FF5B38>}
说说下面这道面试题的功能

  

posted on 2018-12-02 22:49  索静丨LLH  阅读(167)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3