zoukankan      html  css  js  c++  java
  • Python 中 Type 和 Object

    写这篇博文时十分忐忑~ 且谈一下我的认识,有错的欢迎留言指正。

    明确几点

    Python中一切皆对象
    所有的类 都继承自 object,也就是说 object 是所有类的基类(超类)
    type 也继承自 object 源码中type 的定义:class type(object):
    type objcet 的类型 同时 object type 的超类
    明确继承具有传递性。 继承了 家禽 家禽 又继承了 禽类 ,因此鸡也属于禽类,就是这样的关系。
    类和实例关系。类也是对象,在两个对象中,一个是另一个的实例。例如鸡是一个类 叫小红的鸡是鸡的实例。
    在Python3中,类和类型已经是一种东西了
    在Python3 中只有类和非类两种对象。类型是"<class 'type'>" 那么它是类否则它是非类。听起来很绕,英文原文:There are only two kinds of objects in Python: to be unambiguous let's call these types and non-types. Non-types could be called instances, but that term could also refer to a type, since a type is always an instance of another type. Types could also be called classes, and I do call them classes from time to time.

    class Chicken(object):    # 鸡类 他不仅仅是类 也是一个对象,它是 type 的对象
       pass
    
    xiaohong = Chicken()   # 它是鸡类 这个类的对象
    

    Python一切皆对象

    1 在Python中 我们常说的 也是 对象 ,而它们的类是 元类 : type 简单点易于理解称为 类的类

    2 内建的类(类型),object、list、tuple、dict。

    3 自定义的类 MyClass 等等任何你喜欢的名字。

    4 由 自定义的类 内建的类 实例化的对象就是我们常说的 对象 了,也叫对象的实例。

    两种关系

    在面向对象的世界里有两种关系,这与语言本身没有关系,只要是面向对象的语言都拥有这样的两种属性。类型实例关系和继承关系。

    类型实例关系

    即该类由谁创建

    str('abc')  类 str 创建了实例 abc。
    
    class Person(object):
        """ A simple Person class. """
    monkey = Person()
    # monkey  和  Person 就是 类型和实例的关系 type(monkey) --> <class '__main__.Person'>
    

    继承关系

    即类继承自谁

    class MyList(list):
        """ A custom list class , it's a subclass of `list`. """
    # MyList 就是 list 的子类, 它和list 就是 继承关系
    

    type 和 object的关系

    # 这是Python 源码中对type 的定义
    class type(object):
        """
        type(object_or_name, bases, dict)
        type(object) -> the object's type
        type(name, bases, dict) -> a new type
        """
        ...
        
    # 由此 可见 type 是 object 的子类 也就是 继承关系  <1> type 继承自 object
    
    >>> type(object)
    <class 'type'>
    >>> type(type)
    <class 'type'>
    
    # 上面两行代码的输出很清晰  type 和 object 以及 type 与 type 存在 类型实例关系  
    # <2> type 是 object 的类型
    # <3> type 是 type 的类型
    

    一个类/对象的诞生过程

    类和对象的创建十分相似,类 本身也是对象~,他们由元类创建。

    创建类的方法

    class 关键字

    关于这种方式无需赘述,如果下面的代码看不懂,那也没必要继续向下阅读了。

    class MyClass(object):
        """This is a simple class for display how to create a class. """
        name = 'NewClass'
    
        def func(self):
            print('Hello class, my name is %s' % self.name)
    
    
    new_obj = MyClass()
    print(new_obj.func)
    
    # <bound method MyClass.func of <__main__.MyClass object at 0x103b3b2e8>>
    # Hello class, my name is NewClass
    

    type函数

    type 这个函数有点傻屌,它依据参数的不同拥有两种完全不同的行为,在程序设计中是很另类的,似乎也不符合Python的设计哲学。按照Python的 Style 他应该是两个函数才对,但是这是为了更好的向后兼容。

    type 接受三个参数 第一个参数为类的名字, 第二个参数为继承列表, 第三个参数为属性字典(属性和方法)

    def func(self):
        """ A simple function to bound NewClass. """
        print('Hello type, my name is %s' % self.name)
    
    TypeClass = type('TypeClass', (object,), {'name': 'NewClass', 'func': func})
    
    type_obj = TypeClass()
    print(type_obj.func)
    type_obj.func()
    
    # <bound method func of <__main__.NewClass object at 0x100d2f128>>
    # Hello type, my name is TypeClass
    

    看看创建的细节

    到这里我认为你已经对元类 type 有了一定的了解:

    type就是Python在背后用来创建所有类的元类。包括字典 元组 字符串 类 甚至函数等等 都是由type创建。甚至你查看object 的类型也会告诉你他是 type 但是 type又继承自object 源码中写的很清晰。实质上他们都由虚拟机创建,同时objecttype属性是其子类type而type又继承object 不要问先有鸡还是先有蛋~ 你可以抽相处一个类型对象的概念,这个东西 类型是type 父类是object 当然仅仅是概念。不要在这里纠结~ 好吧~ !

    类的创建会调用两个方法, __new__ 和 __init____new__ 用来从类实例化 对象 __init__ 负责实例化这个对象。

    举个不恰当的例子,__new__ 方法就相当于 生孩子,__init__ 方法就相当于给这个孩子起名,上户口这样子。没有 __new__ 就没法__new__ 因此 __new__ 方法一定在 __init__ 之前 而__init__ 需要 __new__ 方法的结果 就是被实例化的对象(就生的那个孩子 没孩子 一切白搭) !

    __call__ 是个神奇的方法, 它允许用户像使用函数那样使用类或对象,也就是使用() 就回来调用__all__

    _call_

    对象通过提供 __call(slef, *args ,**kwargs)__方法可以模拟函数的行为。即允许以类/对象() 的形式来调用。

    元类的__call__方法在继承的类进行实例化时调用(此时实例化出的是个类,而不是对象)

    _new_

    将自身实例化时,也就是创建对象时调用的方法,该方法是一个静态方法,第一个参数为类本身,返回值为为该对象分配的空间。也就是被创建的这个对象。__new__方法至少需要一个cls 参数,表示的是将要被实例化的类本身,需要注意的是该方法必须返回一个空间,也就是返回实例化后的对象 return super().\__new__() 或者 object.__new__()

    _init_

    拿到__new__方法返回的对象,对这个新创建出来的对象进行一些初始化操作。

    优雅的控制类和对象

    使用上述的一些方法我们可以优雅的控制类的创建和使用。例如 我们可以自定义元类来设计优雅的API, 虽然元类的设计麻烦,但是使用其创建的类 使用起来将会非常舒服~ 例如Django 中的model的使用~ 真香~!

    改写类来控制创建的对象

    实现一个配置类,该类需要保证全局只有一个实例,并且需要保证同一时间 配置是一致的。也就是需要保证线程安全。下面是代码,通过控制 __new__ 方法来实现单例。

    import threading
    
    def synchronized(bar):
        """ threading lock for Config"""
        
        bar.__lock__ = threading.Lock()   # get lock
        
        def lock_func(*args, **kwargs):
            with bar.__lock__:
                return bar(*args, **kwargs)
        return lock_func
    
    
    class Config(object):
        """ Singleton `Config` ."""
        _instance = None
    
        @synchronized
        def __new__(cls, *args, **kwargs):
            if cls._instance is None:
                cls._instance = object.__new__(cls, *args, **kwargs)
            return cls._instance
    
    

    改写元类来控制创建的类

    元类所创建的类会拥有元类拥有的方法。

    通常的自定义的元类会重写 __new____call____init__。此时他们的第一个参数不再是对象,而是将要创建的类。__new__ 返回的也将是类, 而 __init__ 是添加类属性而不是实例属性。

    假设上一步的操作中需要将配置类中所有的属性都变为大写的。以 _ 开头的属性除外,要怎么做呢?

    将函数作为元类

    假设上一步的操作中需要将配置类中所有的属性都变为大写的。以 _ 开头的属性除外,要怎么做呢?

    import threading
    
    
    def synchronized(bar):
        """ threading lock for Config"""
    
        bar.__lock__ = threading.Lock()  # get lock
    
        def lock_func(*args, **kwargs):
            with bar.__lock__:
                return bar(*args, **kwargs)
    
        return lock_func
    
    def filter_config(cls_name, cls_mro, cls_attr):
        cls_attr = {k.upper(): v for k, v in cls_attr.items() if not k.startswith('_')}
        return type(cls_name, cls_mro, cls_attr)  # 返回一个类
    
    
    class Config(metaclass=filter_config):  # 指定元类
        """ Singleton `Config` ."""
        _instance = None
    
        @synchronized
        def __new__(cls, *args, **kwargs):
            if cls._instance is None:
                cls._instance = object.__new__(cls, *args, **kwargs)
            return cls._instance
    
        number = 100
        
    config = Config()
    print(config.NUMBER)  # 100
    

    将类作为元类

    import threading
    
    
    def synchronized(bar):
        """ threading lock for Config"""
    
        bar.__lock__ = threading.Lock()  # get lock
    
        def lock_func(*args, **kwargs):
            with bar.__lock__:
                return bar(*args, **kwargs)
    
        return lock_func
    
    
    class Filter_config(type):
        def __new__(cls, cls_name, cls_mro, cls_attr):
            cls_attr = {k.upper(): v for k, v in cls_attr.items() if not k.startswith('_')}
            return super(Filter_config, cls).__new__(cls, cls_name, cls_mro, cls_attr)
    
    
    class Config(metaclass=Filter_config):  # 指定元类
        """ Singleton `Config` ."""
        _instance = None
    
        @synchronized
        def __new__(cls, *args, **kwargs):
            if cls._instance is None:
                cls._instance = object.__new__(cls, *args, **kwargs)
            return cls._instance
    
        number = 100
    
    
    config = Config()
    print(config.NUMBER)  # 100
    
  • 相关阅读:
    使用C++调用并部署pytorch模型
    相位展开(phase unwrapping)算法研究与实践
    【计算机视觉】图像配准(Image Registration)
    读书笔记 - 《数字图像处理》(更新中...)
    ssh框架复习
    SVN 版本控制
    Spring的jdbcTemplate 与原始jdbc 整合c3p0的DBUtils 及Hibernate 对比 Spring配置文件生成约束的菜单方法
    JDK 动态代理 讨债实例
    Spring 框架配置web.xml 整合web struts
    Spring整合JUnit spring静态对象属性的注入
  • 原文地址:https://www.cnblogs.com/monkey-code/p/13159075.html
Copyright © 2011-2022 走看看