Python 面向对象
Posted 超级英雄拯救世界之前成长的日子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 面向对象相关的知识,希望对你有一定的参考价值。
对面向对象的理解?
基础:谈面向对象就要从他的三大特性开始说起,如:封装、继承、多态。 封装: - 方法封装到来类中:某一类功能相似的方法 class File: def file_add():pass def file_update():pass def file_del():pass def file_fetch():pass - 数据封装到对象中 class File: def __init__(self,name,age,email): self.name = name self.age = age self.email = email def file_add():pass def file_update():pass def file_del():pass def file_fetch():pass obj1 = File(‘oldboy‘,19,"[email protected]") obj2 = File(‘oldboy1‘,119,"[email protected]") 应用: - session/request封装到了RequestContext对象中 - app/g封装到了AppContext中 继承:如果多个类中有相同的方法,为了避免重复编写,可以将其放在父类(基类)中。 python支持多继承,继承顺序按__mro__的顺序执行,新式类按广度优先,旧式类类广度优先,Python3都是新式类。先执行左边,在执行右边 class Base(object): def xxxx():pass class File(Base): def __init__(self,name,age,email): self.name = name self.age = age self.email = email def file_add():pass def file_update():pass def file_del():pass def file_fetch():pass class DB(Base): def db_add():pass def db_update():pass def db_del():pass def xxxx():pass def db_fetch():pass 应用: rest framework中的视图类的继承 多态(鸭子模型):天生支持多态,对于参数来说可以传入任何类型的对象,只要保证有想要的send方法即可。 class Msg(object): def send(): pass class WX(object): def send(): pass def func(arg): arg.send()
进阶: __init__,初始化 __new__,创建对象 __call__,对象() __getattr__,对象.xx 且xx不存在 __getattribute__, 对象.xx xx为任何属性 __setattr__. 对象.xx = yy __delattr__, del 对象.xx __setitem__,对象[‘xx‘] = yy __getitem__, 对象[‘xx‘] __delitem__, del 对象[‘xx‘] __mro__,查找成员顺序 __str__, 对象返回值 __repr__, __iter__, 实现此方法,且返回一个迭代器,此对象可迭代 __dict__, 类的成员 __add__, 类 + xx __del__, 对象的生命周期结束之后
高级:metaclass 1. 类创建 class Foo(object):pass Foo = type(‘Foo‘,(object,),{}) 2. 如何指定类由自定义type创建? class MyType(type): pass class Foo(object,metaclass=MyType): # __metaclass__ = MyType # py2 pass Foo = MyType(‘Foo‘,(object,),{}) 3. 默认执行顺序 class Foo(object,metaclass=MyType): pass obj = Foo() class MyType(type): def __init__(self,*args,**kwargs): print(‘111‘) super(MyType,self).__init__(*args,**kwargs) class Base(object, metaclass=MyType): pass class Foo(Base): pass 如果一类自己或基类中指定了metaclass,那么该类就是由metaclass指定的type或mytype创建。 同: class MyType(type): def __init__(self,*args,**kwargs): print(‘111‘) super(MyType,self).__init__(*args,**kwargs) # class Base(object, metaclass=MyType): # pass Base = MyType(‘Base‘,(object,),{}) class Foo(Base): pass 同: class MyType(type): def __init__(self,*args,**kwargs): print(‘111‘) super(MyType,self).__init__(*args,**kwargs) # class Base(object, metaclass=MyType): # pass def with_metaclass(arg): Base = MyType(‘Base‘,(arg,),{}) return Base class Foo(with_metaclass(object)): pass
其他知识
1.创建类的两种方式
方式一:普通方式
In [19]: class Love(object): ...: def love(self): ...: print(‘love‘) ...: In [20]: f = Love() In [21]: f.love() love
方式二:特殊方式
def love(self): print(‘love‘)
f = type(‘Love‘,(object,),{‘func‘:love})
obj = f() obj.func() out:love
In [22]: f
Out[22]: <__main__.Love at 0xdb8e81c048>
In [23]: Love
Out[23]: __main__.Love
2.私有变量
"""
类的私有变量和私有方法
在Python中可以通过在属性变量名前加上双下划线定义属性为私有属性
特殊变量命名
1、 _xx 以单下划线开头的表示的是protected类型的变量。即保护类型只能允许其本身与子类进行访问。若内部变量标示,如: 当使用“from M import”时,不会将以一个下划线开头的对象引入 。 2、 __xx 双下划线的表示的是私有类型的变量。只能允许这个类本身进行访问了,连子类也不可以用于命名一个类属性(类变量),调用时名字被改变(在类FooBar内部,__boo变成_FooBar__boo,如self._FooBar__boo) 3、 __xx__定义的是特列方法。用户控制的命名空间内的变量或是属性,如init , __import__或是file 。只有当文档有说明时使用,不要自己定义这类变量。 (就是说这些是python内部定义的变量名)
在这里强调说一下私有变量,python默认的成员函数和成员变量都是公开的,没有像其他类似语言的public,private等关键字修饰.但是可以在变量前面加上两个下划线"_",这样的话函数或变量就变成私有的.这是python的私有变量轧压(这个翻译好拗口),英文是(private name mangling.) **情况就是当变量被标记为私有后,在变量的前端插入类名,再类名前添加一个下划线"_",即形成了_ClassName__变量名.**
# -*- coding: utf-8 -*- """ @Datetime: 2018/12/30 @Author: Zhang Yafei """ class Obj(object): def __init__(self, name, age): self.name = name self.__age = age def get_age(self): # print(self.__age) return self.__age obj = Obj(‘张亚飞‘,23) print(obj.name) # 张亚飞 # print(obj.__age) # AttributeError: ‘Obj‘ object has no attribute ‘__age‘ print(obj.get_age()) # 23 print(obj._Obj__age) # 23 """私有成员只能类中访问,外部不能直接访问,但若要访问,可以强制访:_类名__var, 或者在内部提供一个接口供外部访问""" class Obj2(Obj): def print_age(self): print(self.__age) obj2 = Obj2(‘张亚飞‘,23) obj2.print_age() # AttributeError: ‘Obj2‘ object has no attribute ‘_Obj2__age‘ """私有字段只能在当前类中访问,其子类也不能访问"""
3. Python内置类属性
__dict__ : 类的属性(包含一个字典,由类的数据属性组成) __doc__ :类的文档字符串 __module__: 类定义所在的模块(类的全名是‘__main__.className‘,如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod) __bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)
class pub(): _name = ‘protected类型的变量‘ __info = ‘私有类型的变量‘ def _func(self): print("这是一个protected类型的方法") def __func2(self): print(‘这是一个私有类型的方法‘) def get(self): return(self.__info) a = pub() print(a._name) a._func() # print(a.info) # 执行结果: # protected类型的变量 # 这是一个protected类型的方法 # protected类型的变量和方法 在类的实例中可以获取和调用 # # print(a.__info) # # a.__func2() # 执行结果: # File "D:/Python/class/class3.py", line 46, in <module> # print(a.__info) # # AttributeError: pub instance has no attribute ‘__info‘ # a.__func2() # AttributeError: pub instance has no attribute ‘__func2‘ # 私有类型的变量和方法 在类的实例中获取和调用不到 # 获取私有类型的变量 print(a.get()) # 执行结果:私有类型的变量 # 如果想要在实例中获取到类的私有类形变量可以通过在类中声明普通方法,返回私有类形变量的方式获取 print(dir(a)) # 执行结果:[‘__doc__‘, ‘__module__‘, ‘_func‘, ‘_name‘, ‘_pub__func2‘, ‘_pub__info‘, ‘get‘] print(a.__dict__) # 执行结果:{} print(a.__doc__) # 执行结果: None print(a.__module__) # 执行结果:__main__ print(a.__bases__) # 执行结果: # print(a.__bases__) # AttributeError: pub instance has no attribute ‘__bases__‘
面向对象知识深入:
-*- coding: utf-8 -*- """ @Datetime: 2018/12/29 @Author: Zhang Yafei """ """方式一""" # my_singleton.py # # class Singleton(object): # pass # # singleton = Singleton() # # from mysingleton import singleton """方式二:使用装饰器""" # def Singleton(cls): # _instance = {} # # def _singleton(*args, **kargs): # if cls not in _instance: # _instance[cls] = cls(*args, **kargs) # return _instance[cls] # # return _singleton # # # @Singleton # class A(object): # a = 1 # # def __init__(self, x=0): # self.x = x # # # a1 = A(2) # a2 = A(3) """方式三:使用类""" # import threading # import time # # # class Singleton(object): # # def __init__(self): # # time.sleep(1) # pass # @classmethod # def instance(cls, *args, **kwargs): # if not hasattr(Singleton, "_instance"): # Singleton._instance = Singleton(*args, **kwargs) # return Singleton._instance # # # def task(arg): # obj = Singleton.instance() # print(obj) # # # for i in range(10): # t = threading.Thread(target=task,args=[i,]) # t.start() """解决方法:加锁""" # import time # import threading # # # class Singleton(object): # _instance_lock = threading.Lock() # # def __init__(self): # time.sleep(1) # # @classmethod # def instance(cls, *args, **kwargs): # if not hasattr(Singleton, "_instance"): # with Singleton._instance_lock: # if not hasattr(Singleton, "_instance"): # Singleton._instance = Singleton(*args, **kwargs) # return Singleton._instance # # # # # def task(arg): # obj = Singleton.instance() # print(obj) # # for i in range(10): # t = threading.Thread(target=task,args=[i,]) # t.start() # time.sleep(20) # obj = Singleton.instance() # print(obj) """方法四:基于__new__方法""" # # import threading # # class Singleton(object): # _instance_lock = threading.Lock() # # def __init__(self): # pass # # def __new__(cls, *args, **kwargs): # if not hasattr(Singleton, "_instance"): # with Singleton._instance_lock: # if not hasattr(Singleton, "_instance"): # Singleton._instance = object.__new__(cls) # return Singleton._instance # # # obj1 = Singleton() # obj2 = Singleton() # print(obj1,obj2) # # # def task(arg): # obj = Singleton() # print(obj) # # # for i in range(10): # t = threading.Thread(target=task,args=[i,]) # t.start() # """方法五:元类实现单例模式""" import threading class SingletonType(type): _instance_lock = threading.Lock() def __call__(cls, *args, **kwargs): if not hasattr(cls, "_instance"): with SingletonType._instance_lock: if not hasattr(cls, "_instance"): cls._instance = super(SingletonType,cls).__call__(*args, **kwargs) return cls._instance class Foo(metaclass=SingletonType): def __init__(self,name): self.name = name obj1 = Foo(‘name‘) obj2 = Foo(‘name‘) print(obj1,obj2)
class Obj4(): def __enter__(self): print(‘__enter__‘) def __exit__(self, exc_type, exc_val, exc_tb): print(‘__exit__‘) with Obj4(): print(‘执行中‘) # __enter__ # 执行中 # __exit__ """with 对象默认执行__enter__方法,执行结束执行__exit__方法"""
# -*- coding: utf-8 -*- """ @Datetime: 2018/10/14 @Author: Zhang Yafei """ class Obj(object): """限制对象添加属性""" __slots__ = [‘storage‘, ‘stack_func‘, ‘num‘, ‘name‘] def __init__(self): """ 创建对象的时候若new返回一个对象会执行此方法 类名()""" object.__setattr__(self, ‘storage‘, {}) print(‘__init__‘) def __new__(cls, *args, **kwargs): """创建对象的时候会执行,返回一个对象 应用:单例/rest framework序列化 """ print(‘__new__‘) return super(Obj, cls).__new__(cls, *args, **kwargs) def __call__(self): """ 对象()会执行 应用:flask源码请求入口,django请求入口(WSGIHandler.__call__) """ print(‘__call__‘) def __str__(self): """ 调用对象会执行此函数 :return: string_obj 返回一个字符串对象 """ return ‘__str__‘ def __repr__(self): """ 转化为机器可以解释的语言 """ return ‘__repr__‘ def __getattr__(self, item): """当访问不存在的属性时会调用""" return ‘__getattr__‘ def __setattr__(self, key, value): """给对象设置属性的时候会调用""" # self.key = value #容易出现循环调用 print(‘__setattr__‘) if key == ‘num‘: object.__setattr__(self, key, value - 100) else: object.__setattr__(self, key, value) def __delattr__(self, item): """删除属性的时候会调用""" print(‘__delattr__‘) object.__delattr__(self, item) def __getattribute__(self, item): """访问任何属性的时候都会调用此方法""" print(‘__getattribute__‘) return super(Obj, self).__getattribute__(item) def __del__(self): """对象的生命周期执行结束之后执行""" print(‘__del__‘) def __setitem__(self, key, value): """obj[key] = value时会调用此方法""" print(‘__setitem__‘) self.storage[key] = value def __getitem__(self, key): """obj[key]会调用此方法""" return self.storage.get(key, None) def __delitem__(self, key): """del obj[key]调用""" print(‘__delitem__‘) del self.storage[key] def __add__(self, other): return ‘__add__‘ def __sub__(self, other): return ‘__sub__‘ def __mul__(self, other): return ‘__mul‘ def __floordiv__(self, other): return ‘__floatdiv__‘ def __mod__(self, other): return ‘__mod__‘ def __divmod__(self, other): return ‘__divmod__‘ def __pow__(self, power, modulo=None): return ‘__pow__‘ obj = Obj() # __new__ __init__ print(obj) # __str__ obj() # __call__ print(Obj.__mro__) # (<class ‘__main__.Obj‘>, <class ‘object‘>) obj.name = ‘__dict__‘ print(obj.__dict__) # print(Obj.__dict__) print(repr(obj)) # __repr__ print(obj.world) # __getattribute__ __getattr__ obj.num = 200 # __setattr__ print(obj.num) # __getattribute__, 100 del obj.num # __delattr__ print(obj.storage) # {} obj[‘name‘] = ‘张亚飞‘ # __setitem__ print(obj.storage) # __getattrbute__ __getattrbute__ {‘name‘:‘张亚飞‘} print(obj[‘name‘]) # __getattrbute__ 张亚飞 del obj[‘name‘] # __delitem__ print(obj[‘name‘]) # __getitem__, __getitem__, None print(obj + 7) print(obj - 1) print(obj * 1) print(obj // 1) print(obj % 3) print(obj.__divmod__(3)) print(obj.__pow__(2)) # __del__ """ 这里我们想让__setattr__执行默认行为,也就是将value赋值给name,和object对象中的同样方法,做类似的操作。 但是这里我们不调用父类__setattr__的方法来实现,做这样的尝试得到的结果就是,超过循环调用深度,报错。因为 这里在执行初始化方法self.world = world的时候,就会调用__setattr__方法,而这里的__setattr__方法里面的 self.name = value又会调用自身。所以造成了循环调用。所以使用该魔法方法的时候要特别注意。 """ class Friends(object): def __init__(self): self.name = ‘zhang‘ self.age = 23 def func(self): print(‘__func__‘) class Xiaoming(Friends): score = 99 def __init__(self): super(Xiaoming, self).__init__() self.run = 200 if __name__ == ‘__main__‘: # 一些内置数据类型没有__dict__属性 ll = [] dic = {} num = 3 # print(ll.__dict__) # AttributeError: ‘list‘ object has no attribute ‘__dict__‘ # print(dic.__dict__) # print(num.__dict__) # 类的__dict__和对象的__dict__的区别 f = Friends() # 创建实例 print(f.__dict__) f.message = ‘hello world‘ f.func = lambda x:x print(f.__dict__) print(Friends.__dict__) # 继承关系的__dict__ xiaoming = Xiaoming() print(xiaoming.__dict__) print(Xiaoming.__dict__) """ 1. 一些内置数据类型没有__dict__ 2. 实例的__dict__存有与实例相关的实例变量和函数. 类的__dict__则是和实例共享的变量,函数(方法,类属性).注意,类的__dict__并不包含其父类的属性. 3. 对象也有自己的__dict__属性, 存储self.xxx 信息,父子类对象公用__dict__ """ class BAR(object): def __init__(self, cls): self.cls = cls class NEW_OBJ(object): def __new__(cls, *args, **kwargs): # return super(NEW_OBJ, cls).__new__(cls, *args, **kwargs) # <__main__.NEW_OBJ object at 0x000000D445061CF8> # return 123 # 123 # return BAR # <class ‘__main__.BAR‘> # return BAR() # <__main__.BAR object at 0x000000AD77141C50> return BAR(cls) # <__main__.BAR object at 0x0000003BFFA31D68> obj = NEW_OBJ() print(obj) """new方法的返回值决定对象到底是什么"""
class Obj(object): def __iter__(self): # return iter([1,2,3]) yield 1 yield 2 yield 3 obj = Obj() for item in obj: print(item)
# -*- coding: utf-8 -*- """ @Datetime: 2018/12/30 @Author: Zhang Yafei """ """创建类的两种方式""" class Obj(object): x = 123 def func(self): return 666 Obj1 = type(‘Obj1‘,(object,),{‘x‘:123,‘func‘:lambda self:666}) obj = Obj() obj1 = Obj1() print(obj.x, obj.func()) print(obj1.x,obj1.func()) """2.自定义type""" class MyType(type): pass class Obj(object, metaclass=MyType): x = 123 def func(self): return 666 Obj2 = MyType(‘Obj2‘,(object,),{‘x‘:123,‘func‘: lambda self:666}) # 注意:metaclass的作用是制定当前类由谁创建, 默认是由type创建 """3.metaclass""" class MyType(type): def __init__(self, *args, **kwargs): print(‘MyType的__init__‘) super(MyType, self).__init__(*args, **kwargs) def __call__(cls, *args, **kwargs): print(‘MyType的__call__‘) obj3 = cls.__new__(cls) cls.__init__(obj3) return obj class Obj3(object, metaclass=MyType): x = 123 def __init__(self): print(‘Obj3的__init__‘) def __new__(cls, *args, **kwargs): print(‘Obj3的__new__‘) return object.__new__(cls) def func(self): return 666 # print(Obj3) # MyType的__init__ <class ‘__main__.Obj3‘> obj3 = Obj3() # MyType的__init__ MyType的__call__ Obj3的__new__ Obj3的__init__ # obj3 = Obj3() # Obj3是类 # Obj3是MyType的一个对象 """ 1. 创建类时,先执行metaclass(默认为type)的__init__方法 2. 类在实例化时, 执行metaclass(默认为type)的__call__方法,__call__方法的返回值就是实例化的对象 __call__内部调用: - 类.__new__方法:创建对象 _ 类.__init__方法:对象的初始化 """ class MyType(type): def __init__(self, *args, **kwargs): print(‘mytype__init__‘) super(MyType, self).__init__(*args,**kwargs) # class Base(object, metaclass=MyType): # pass # class Obj4(Base): # pass def with_metaclass(arg): Base = MyType(‘Base‘,(arg,),{}) # class Base(arg, metaclass=MyType): # pass return Base class Obj4(with_metaclass(object)): pass
以上是关于Python 面向对象的主要内容,如果未能解决你的问题,请参考以下文章