zoukankan      html  css  js  c++  java
  • Python面向对象几个知识点

    一、判断对象是否属于类、判断类是否派生自某个类

    class Zero:
        pass
    
    
    class One(Zero):
        pass
    
    
    class Two(One, Zero):
        pass
    
    
    # 判断对象是否完全是某个类
    print(type(Two()) == Two)#true
    print(type(Two()) == Zero)#false
    # 判断对象是否属于某个类
    print(isinstance(Two(), Zero))#true
    # 判断某个类是否是另一个类的子类
    print(Zero in Two.__bases__)#true
    print(issubclass(Two,Zero))
    

    二、关于元类

    在Python中,类型分为三个层次:元类、类、对象。
    类是元类的实例化,对象是类的实例化。
    在Python中,元类、类、对象三种东西相当于结点,它们之间的有向边表示继承关系。整个类型系统构成一个有向无环图。这个有向无环图分为三层,一个对象可以继承多个类。

    metaclass的作用就是创建类
    举一个小例子

    class BaseMetaClass(type):
        def __new__(cls, *args, **kwargs):
            kind = type.__new__(cls, *args, **kwargs)
            print(kind)
            return kind
    
    
    class Base(metaclass=BaseMetaClass):
        pass
    
    
    class One(Base):
        pass
    
    
    class Two(Base):
        pass
    
    

    输出为

    <class '__main__.Base'>
    <class '__main__.One'>
    <class '__main__.Two'>
    

    在此例中,只进行了类的声明,没有进行类的实例化。在进行类的声明过程中,会调用metaclass的new方法,new方法的返回值就是一个具体的类型。类型是特殊的对象。
    Python中,内置函数type起的作用非常关键,它具有两个作用

    • type(obj)查看obj的类型,type(cls)查看cls的元类
    • type(className,*arg,*karg)构造函数产生新的类

    在上述代码的基础上加几句话

    class Three:
        pass
    print(type(One))#<class '__main__.BaseMetaClass'>
    print(type(Three))#<class 'type'>
    print(type(type))#<class 'type'>
    

    三、一切皆type

    在Java中,一切皆是Object
    在Python中,一切皆是type

    def f():
        pass
    
    
    ff = lambda: 0
    x = []
    for i in (list, dict, type, f, ff, x):
        while type(i) != i:
            print(i, end=' ')
            i = type(i)
        print(i)
    
    

    输出为

    <class 'list'> <class 'type'>
    <class 'dict'> <class 'type'>
    <class 'type'>
    <function f at 0x000000CEE01B7F28> <class 'function'> <class 'type'>
    <function <lambda> at 0x000000CEE07E5A60> <class 'function'> <class 'type'>
    [] <class 'list'> <class 'type'>
    

    四、函数中可以定义类,类中可以定义函数

    函数是function类型,function是type类型

    >>> def choose_class(name):
    …       if name == 'foo':
    …           class Foo(object):
    …               pass
    …           return Foo     # 返回的是类,不是类的实例
    …       else:
    …           class Bar(object):
    …               pass
    …           return Bar
    …
    >>> MyClass = choose_class('foo')
    >>> print MyClass              # 函数返回的是类,不是类的实例
    <class '__main__'.Foo>
    >>> print MyClass()            # 你可以通过这个类创建类实例,也就是对象
    <__main__.Foo object at 0x89c6d4c>
    

    五、使用type定义类型

    type(类型名称,基类列表,属性字典)

    A = type("A", (), {
        'name': 'weidiao',
        'age': 23,
        '__str__': lambda self: '{},{}'.format(self.name, self.age)
    })
    x = A()
    print(x)#输出为weidiao,23
    
    

    六、__class__属性

    __class__属性时是每一种类型必然包含的属性,该属性的取值相当于x.__class==type(x)

    七、不要忘记python是一门脚本语言

    下面定义了一个类A,它有name和age两个属性,但是我可以随意给这个对象添加属性。

    A = type("A", (), {
        'name': 'weidiao',
        'age': 23,
        '__str__': lambda self: '{},{},{}'.format(self.name, self.age,self.baga)#如果没有baga属性,此处会报错
    })
    x = A()
    x.baga='3'
    print(x)
    

    八、调用父类构造函数的两种方法

    在Java和C++中,子类的构造函数都会自动调用父类的构造函数。
    在Python中,子类是不会自动调用父类的构造函数的,因为在Python中没有构造函数,而只有初始化函数!而初始化函数只相当于普普通通的函数,所以,这就需要我们手动来调用父类的构造函数。
    首先来看,如果不调用父类构造函数会出现什么情况

    class A:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __str__(self):
            return self.name + str(self.age)
    
    
    class B(A):
        def __init__(self):
            pass
    
    
    b = B()
    print(b)
    

    在此例中,B类没有调用A类的初始化函数,所以B类就缺少了name和age属性,B类的str相当于A类的str,print时就会因为缺少name和age属性报错

    AttributeError: 'B' object has no attribute 'name'
    

    有两种方法调用父类的构造函数

    class A:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __str__(self):
            return self.name + str(self.age)
    
    
    class B(A):
        def __init__(self):
            # A.__init__(self,'weidiao',23)
            super(B,self).__init__('weidiao',23)
    
    
    b = B()
    print(b)
    
    

    这两种方法第一种方法比较灵活,完全可以取代第二种方法。
    A.__init__(self,args)这种方式只初始化了父类A
    super(B,self).__init__(self,args)这种方式初始化了第一个父类(根据继承的顺序),所以这种方式是完全可以用FirstFather.__init()进行取代的。

    九、单例

    Java中的对象的创建和对象的初始化这两个过程是紧密耦合在一起的,对象创建过程指的是为对象分配必要的内存空间,对象初始化指的是向内存中写入值。简言之,Java中一旦调用构造函数,对象空间开辟和对象初始化两种操作就同时完成了。在Java中,单例只创建一次且只初始化一次。
    在Python中不是这样,Python中对象创建过程和对象初始化过程是分开的。class的__new__()函数负责对象的创建,class的__init__()负责对象的初始化。在Python中,单例可能创建一次,初始化多次。

    下面看一种单例的写法:

    class Dog:
        dog = None
    
        def __new__(cls, *args, **kwargs):
            if cls.dog is None:
                cls.dog = object.__new__(cls)
                print('create singleton over')
            return cls.dog
    
        def __init__(self, name):
            print('init is called')
            self.name = name
    
    
    # 下面这句话会报错,因为Dog.dog目前为None
    # print(Dog.dog.name)
    x = Dog('x')
    y = Dog('y')
    print(x.name)  # y
    print(y.name)  # y
    

    此例中,会发现init is called输出两次,但是x和y实际上是同一个对象。也就是说,在Python中,只要调用对象的构造函数,必然会先调用__new__()函数,__new__()返回一个对象,然后Python会自动调用返回对象的__init__()函数。

    上面例子的另一种实现是把重写new函数的工作放到一个父类里面,这样就能够实现:只需要继承父类就能够让自己变成单例。

    class Singleton:
        _instance = None
    
        def __new__(cls, *args, **kwargs):
            if not cls._instance:
                cls._instance = object.__new__(cls)
            return cls._instance
    
    
    class Dog(Singleton):
        def __init__(self, name):
            self.name = name
    
    
    x = Dog('x')
    y = Dog('y')
    print(x.name, y.name)
    
    

    在Python中,我们创建的任何一个对象,无需重写setattr方法即可随便往对象上“悬挂”成员变量。

    class Ha:
        pass
    
    x = Ha()
    x.dog = 3
    print(x.dog)
    

    单例的实现

    from functools import lru_cache
    
    
    class Singleton:
        @lru_cache()
        def __new__(cls, *args, **kwargs):
            obj = object.__new__(cls)
            obj.inited = False
            return obj
    
    
    class Haha(Singleton):
        def __init__(self, name):
            if self.inited:
                return
            self.inited = True
            self.name = name
            print("inited")
    
    
    x = Haha("x")
    y = Haha("y")
    print(x.name)
    print(y.name)
    
    

    总结

    在语言的完美、统一程度上,Python无人可及,Java都比它差一点。

  • 相关阅读:
    Codeforces Round #545 (div 1.)
    THUSC 2017 大魔法师
    loj #6216. 雪花挂饰
    [NOI Online #2 提高组]涂色游戏
    [NOI Online #2 提高组]子序列问题
    [NOI Online #1 入门组]跑步
    备战noip week7
    [NOI Online #3 提高组]优秀子序列
    20201017校测
    springboot基于maven多模块项目搭建(直接启动webApplication)
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/8086504.html
Copyright © 2011-2022 走看看