面向对象进阶

__getitem__,__getattr__

__getattr__内置使用点号获取实例属性属性如 s.name,自调用__getattr__
__setattr__设置类实例属性 如s.name='tom',自调用__setattr__
__getitem__ 使用[]获取实例属性 如s['name'],自调用__getitem__
__setitem__ 使用[]设置实例属性如 s['name'] = 'tom' ,自调用__setitem__
__dict__ 为参数字典

如下代码:

class Student:
    def __getattr__(self, item):
        return item + ' is not exits'

    def __setattr__(self, key, value):
        self.__dict__[key] = value

    def __getitem__(self, item):
        return self.__dict__[item]

    def __setitem__(self, key, value):
        self.__dict__[key] = value

s = Student()
print(s.name)  # 调用__getattr__方法 输出'name is not exits'
s.age = 1  # 调用__setattr__ 方法
print(s.age)  # 输出 1
print(s['age'])  # 调用 __getitem__方法 输出1
s['name'] = 'tom'  # 调用 __setitem__ 方法
print(s['name'])  # 调用 __getitem__ 方法 输出 'tom'

把模块当做脚本执行 

我们可以通过模块的全局变量__name__来查看模块名:
当做脚本运行:
__name__ 等于'__main__'

当做模块导入:
__name__= 模块名

作用:用来控制.py文件在不同的应用场景下执行不同的逻辑
if __name__ == '__main__':

isinstance和issubclass

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

class Foo(object):
     pass
  
obj = Foo()
  
isinstance(obj, Foo)

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

class Foo(object):
    pass
 
class Bar(Foo):
    pass
 
issubclass(Bar, Foo)

反射

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 Foo:
 2     f = '类的静态变量'
 3     def __init__(self,name,age):
 4         self.name=name
 5         self.age=age
 6 
 7     def say_hi(self):
 8         print('hi,%s'%self.name)
 9 
10 obj=Foo('egon',73)
11 
12 #检测是否含有某属性
13 print(hasattr(obj,'name'))
14 print(hasattr(obj,'say_hi'))
15 
16 #获取属性
17 n=getattr(obj,'name')
18 print(n)
19 func=getattr(obj,'say_hi')
20 func()
21 
22 print(getattr(obj,'aaaaaaaa','不存在啊')) #报错
23 
24 #设置属性
25 setattr(obj,'sb',True)
26 setattr(obj,'show_name',lambda self:self.name+'sb')
27 print(obj.__dict__)
28 print(obj.show_name(obj))
29 
30 #删除属性
31 delattr(obj,'age')
32 delattr(obj,'show_name')
33 delattr(obj,'show_name111')#不存在,则报错
34 
35 print(obj.__dict__)
四个方法的使用演示
 1 class Foo(object):
 2  
 3     staticField = "old boy"
 4  
 5     def __init__(self):
 6         self.name = 'wupeiqi'
 7  
 8     def func(self):
 9         return 'func'
10  
11     @staticmethod
12     def bar():
13         return 'bar'
14  
15 print getattr(Foo, 'staticField')
16 print getattr(Foo, 'func')
17 print getattr(Foo, 'bar')
类也是对象
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import sys
 5 
 6 
 7 def s1():
 8     print 's1'
 9 
10 
11 def s2():
12     print 's2'
13 
14 
15 this_module = sys.modules[__name__]
16 
17 hasattr(this_module, 's1')
18 getattr(this_module, 's2')
反射当前模块成员

导入其他模块,利用反射查找该模块是否存在某个方法

1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3 
4 def test():
5     print('from the test')
View Code
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3  
 4 """
 5 程序目录:
 6     module_test.py
 7     index.py
 8  
 9 当前文件:
10     index.py
11 """
12 
13 import module_test as obj
14 
15 #obj.test()
16 
17 print(hasattr(obj,'test'))
18 
19 getattr(obj,'test')()
View Code

__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 class Foo:
 2 
 3     def __del__(self):
 4         print('执行我啦')
 5 
 6 f1=Foo()
 7 del f1
 8 print('------->')
 9 
10 #输出结果
11 执行我啦
12 ------->
简单示范

item系列

__getitem__\__setitem__\__delitem_

class Foo:
    def __init__(self,name):
        self.name=name

    def __getitem__(self, item):
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        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')
f1['age']=18
f1['age1']=19
del f1.age1
del f1['age']
f1['name']='alex'
print(f1.__dict__)

__new__

 1 class A:
 2     def __init__(self):
 3         self.x = 1
 4         print('in init function')
 5     def __new__(cls, *args, **kwargs):
 6         print('in new function')
 7         return object.__new__(A, *args, **kwargs)
 8 
 9 a = A()
10 print(a.x)
View Code
 1 class Singleton:
 2     def __new__(cls, *args, **kw):
 3         if not hasattr(cls, '_instance'):
 4             cls._instance = object.__new__(cls, *args, **kw)
 5         return cls._instance
 6 
 7 one = Singleton()
 8 two = Singleton()
 9 
10 two.a = 3
11 print(one.a)
12 # 3
13 # one和two完全相同,可以用id(), ==, is检测
14 print(id(one))
15 # 29097904
16 print(id(two))
17 # 29097904
18 print(one == two)
19 # True
20 print(one is two)
单例模式

__call__

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

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

 1 class Foo:
 2 
 3     def __init__(self):
 4         pass
 5     
 6     def __call__(self, *args, **kwargs):
 7 
 8         print('__call__')
 9 
10 
11 obj = Foo() # 执行 __init__
12 obj()       # 执行 __call__
View Code

__len__

1 class A:
2     def __init__(self):
3         self.a = 1
4         self.b = 2
5 
6     def __len__(self):
7         return len(self.__dict__)
8 a = A()
9 print(len(a))
View Code

__hash__

1 class A:
2     def __init__(self):
3         self.a = 1
4         self.b = 2
5 
6     def __hash__(self):
7         return hash(str(self.a)+str(self.b))
8 a = A()
9 print(hash(a))
View Code

__eq__

 1 class A:
 2     def __init__(self):
 3         self.a = 1
 4         self.b = 2
 5 
 6     def __eq__(self,obj):
 7         if  self.a == obj.a and self.b == obj.b:
 8             return True
 9 a = A()
10 b = A()
11 print(a == b)
View Code
 1 class FranchDeck:
 2     ranks = [str(n) for n in range(2,11)] + list('JQKA')
 3     suits = ['红心','方板','梅花','黑桃']
 4 
 5     def __init__(self):
 6         self._cards = [Card(rank,suit) for rank in FranchDeck.ranks
 7                                         for suit in FranchDeck.suits]
 8 
 9     def __len__(self):
10         return len(self._cards)
11 
12     def __getitem__(self, item):
13         return self._cards[item]
14 
15 deck = FranchDeck()
16 print(deck[0])
17 from random import choice
18 print(choice(deck))
19 print(choice(deck))
纸牌游戏
 1 class FranchDeck:
 2     ranks = [str(n) for n in range(2,11)] + list('JQKA')
 3     suits = ['红心','方板','梅花','黑桃']
 4 
 5     def __init__(self):
 6         self._cards = [Card(rank,suit) for rank in FranchDeck.ranks
 7                                         for suit in FranchDeck.suits]
 8 
 9     def __len__(self):
10         return len(self._cards)
11 
12     def __getitem__(self, item):
13         return self._cards[item]
14 
15     def __setitem__(self, key, value):
16         self._cards[key] = value
17 
18 deck = FranchDeck()
19 print(deck[0])
20 from random import choice
21 print(choice(deck))
22 print(choice(deck))
23 
24 from random import shuffle
25 shuffle(deck)
26 print(deck[:5])
纸牌游戏2
 1 class Person:
 2     def __init__(self,name,age,sex):
 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:return True
12 
13 
14 p_lst = []
15 for i in range(84):
16     p_lst.append(Person('egon',i,'male'))
17 
18 print(p_lst)
19 print(set(p_lst))
一道面试题
原文地址:https://www.cnblogs.com/caochao-/p/8516841.html