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,"asdf@live.com")
            obj2 = File('oldboy1',119,"asdf12@live.com")
        
        應用:
            - django rest_framework中對request進行封裝       request = self.initialize_request(request, *args, **kwargs)
            - session/request封裝到了RequestContext對象中     ctx = RequestContext()
            - app/g封裝到了AppContext中              app_ctx = 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__, 對象的生命週期結束以後  
# -*- 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):
        """
        轉化爲機器能夠解釋的語言
        case 1: repr(object)時會執行此函數
        case 2: 交互模式下打印對象會執行此函數
        :return: 用於對象信息的顯示
        """
        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方法的返回值決定對象究竟是什麼"""
進階:python面向對象的魔法方法

高級:metaclass

metaclass:指定類由那個type建立?(type泛指繼承type的全部類)
    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
# -*- 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
高級:metaclass的內部實現

其餘知識

1.建立類的兩種方式

方式一:普通方式前端

In [19]: class Love(object):
    ...:     def love(self):
    ...:         print('love')
    ...: 

In [20]: f = Love()

In [21]: f.love()
love

方式二:特殊方式python

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>django

 
 

In [23]: Love
Out[23]: __main__.Loveflask

 

 2.私有屬性

"""微信

類的私有變量和私有方法session

在Python中能夠經過在屬性變量名前加上雙下劃線定義屬性爲私有屬性app

特殊變量命名ide

一、 _xx 以單下劃線開頭的表示的是protected類型的變量。即保護類型只能容許其自己與子類進行訪問。若內部變量標示,如: 當使用「from M import」時,不會將以一個下劃線開頭的對象引入 。

二、 __xx 雙下劃線的表示的是私有類型的變量。只能容許這個類自己進行訪問了,連子類也不能夠用於命名一個類屬性(類變量),調用時名字被改變(在類FooBar內部,__boo變成_FooBar__boo,如self._FooBar__boo)

三、 __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__'
內置類屬性

 4. 約束

Java:fetch

  • 接口,約子類中必須包含某個方法(約束)。
  • 抽象方法/抽象類,約子類中必須包含某個方法。(約束+繼承)
Interface IMessage:
    def func1(self):
        pass 
    def func2(self):
        pass 
        
class Msg(IMessage):
    def func1(self):
        print('func1') 
    def func2(self):
        print('func1') 
接口
class abstract IMessage:
    def abstract func1(self):
        pass 
    def abstract func2(self):
        pass 
    
    def func3(self):
        print('asdfasdf') 
        
class Msg(IMessage):
    def func1(self):
        print('func1') 
    def func2(self):
        print('func1') 
抽象類

Python

  • - 接口(無)
  • - 抽象方法/抽象類(有,ABC)
  • - 類繼承+異常
import abc


class Base(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def send(self):pass

    def func(self):
        print(123)


class Foo(Base):

    def send(self):
        print('發送信息')


obj = Foo()
obj.send()
obj.func()
抽象方法/抽象類
類繼承+異常

  做用:的用於告知其餘人之後繼承時,須要實現那個方法

class BaseAuthentication(object):
"""
All authentication classes should extend BaseAuthentication.
"""

    def authenticate(self, request):
        """
        Authenticate the request and return a two-tuple of (user, token).
        """
        raise NotImplementedError(".authenticate() must be overridden.")

    def authenticate_header(self, request):
        """
        Return a string to be used as the value of the `WWW-Authenticate`
        header in a `401 Unauthenticated` response, or `None` if the
        authentication scheme should return `403 Permission Denied` responses.
        """
        pass
rest_framework示例
class BaseMessage(object):

    def send(self):
        raise NotImplementedError('必須實現send方法')


class Msg(BaseMessage):
    def send(self):
        print('發送短信')


class Wechat(BaseMessage):
    def send(self):
        print('發送微信')


class Email(BaseMessage):
    def send(self):
        print('發送郵件')



class DingDing(BaseMessage):
    def send(self):
        print('發送釘釘提醒')
發送消息示例

 面向對象知識深刻:

 -*- 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__方法"""
with對象的本質
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)
對象能夠被for循環
相關文章
相關標籤/搜索