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
高级:metaclass

  其他知识                                

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__方法"""
with对象的本质
技术分享图片
# -*- 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方法的返回值决定对象到底是什么"""
python面向对象
技术分享图片
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循环
技术分享图片
# -*- 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

 







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

python之路之前没搞明白4面向对象(封装)

Python面向对象学习之八,装饰器

python:第二部分:面向对象:面向对象object orinted

Python 面向对象

面向面试编程代码片段之GC

面向对象编程其实很简单——Python 面向对象(初级篇)