object类

object是一个基类,或称之为元类。在python2.x上,不继承object类的称之为经典类,继承了object类的称之为新式类。

在python3种默认都是新式类,也即是所有的自定义类、基类都会继承object类。

object类里面内置了许多函数,下面一一讲解:

1. __dir__:返回一个列表,其中包含所有的属性和方法名(包含特殊方法)。函数原型如下:

def __dir__(self, *args, **kwargs):
    """ Default dir() implementation. """
    pass

   下面举一个例子:

class Test():
    pass

print(Test().__dir__())  # 也可执行 dir(obj) 来获取所有属性和方法

"""
输出如下:
['__module__', '__dict__', '__weakref__', '__doc__', '__repr__', 
 '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', 
 '__lt__', '__le__', '__eq__', '__ne__', '__gt__', 
 '__ge__', '__init__', '__new__', '__reduce_ex__', '__reduce__', 
 '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
"""

 

2. __setattr__:当我们执行obj.属性名=属性值setattr(obj,属性名,属性值),即为属性赋值时被调用。

class Foo(object):
    def __init__(self):
        self.name = 'Alex'   # 打印 call __setattr__

    # 重写__setattr__,为了使调用时打印输出,obj.xxx = value时调用
    def __setattr__(self, key, value):
        print('call __setattr__')
        return object.__setattr__(self, key, value)  # 调用基类的方法来赋值

f = Foo()
f.name = 'Jone'  # 打印 call __setattr__

 

3. __getattribute__和__getattr__:使用类的对象进行obj.属性名getattr(obj,属性名)来取对象属性的值的时候被调用,不管属性是否存在,

   __getattribute__方法都会被调用。如果属性存在,则返回该属性的值,如果属性不存在,则返回None。我们在使用hasattr(obj,属性名)来判断

   某个属性是否存在时,__getattribute__方法也会被调用。

   与__getattr__的区别:

   __getattribute__方法不管属性是否存在,都会被调用。而__getattr__只在属性不存在时调用,默认会抛出:

   'AttributeError: xxx object has no attribute yyy'这样的错误,但我们可以对其进行重写,做我们需要的操作。

class Test(object):
    def __init__(self):
        self.name = 'Alex'

    def __getattribute__(self, item):
        print("call __getattribute__")
        return object.__getattribute__(self, item)

    def __getattr__(self, item):
        print('call __getattr__')
        print("%s不存在,但我可以返回一个值" % item)
        return 54

f = Test()
print(f.name)  # name 属性存在,打印 call __getattribute__
print(f.age)   # age 属性不存在,打印 call __getattribute__,会返回None,
               # 然后打印 call __getattr__, 但 __getattr__ 方法返回了54(如果没有被重写,则直接报异常),所以这里打印54。

 

4. __str__和__repr__:默认打印的是对象的内存地址等信息。

   1)只重写__str__,则只能用于定义print(obj)时打印的内容,交互式命令行输出obj还是函数地址。

>>> class Foo(object):
...     def __str__(self):
...         return "我是Foo"
...
>>> f1 = Foo()
>>> print(f1)
我是Foo
>>> f1
<__main__.Foo object at 0x0000023BF701C550>

   2)只重写__repr__,则用于同时定义python命令行输出obj的内容,以及print(obj)的打印内容。

>>> class Foo(object):
...     def __repr__(self):
...         return "我是Foo"
...
>>> f1 = Foo()
>>> print(f1)
我是Foo
>>> f1
我是Foo

   3)如果__str__和__repr__都被重写了,则__str__负责print的信息,而__repr__负责命令行直接输出obj的信息。

>>> class Foo():
...     def __str__(self):
...         return "我是Foo---str"
...     def __repr__(self):
...         return "我是Foo---repr"
...
>>> f1 = Foo()
>>> print(f1)
我是Foo---str
>>> f1
我是Foo---repr

  

5. __new__:__new__方法是一个静态方法,在调用时,传入你需要实例化的类名以及初始化参数列表,创建一个cls类的对象,并返回。其函数原型如下:

@staticmethod
def __new__(cls, *more):
    """ Create and return a new object.  See help(type) for accurate signature. """
    pass

   注意以下几点:

    1)__new__在object被指定为@staticmethod,但更像是一个@classmethod,第一个参数传入类本身cls。

    2)__new__在__init__之前运行,为传入的类(Foo)生成一个实例并返回。

    3)__init__在__new__之后执行,为__new__返回的类实例进行初始化。

    4)__init__是一个实例方法,是由实例来调用的。所以要执行__init__方法,必须先要由__new__生产一个实例。这就是为什么先执行__new__方法的原因。

class Foo(object):
    # 后于__new__方法执行,为__new__方法生成的对象进行初始化
    def __init__(self, name, age):  # __new__返回的对象作为self传入__init__
        print("执行__init__方法")
        self.name = name
        self.age = age

    # __new__方法先于__init__方法执行,用于生成一个指定类的对象
    def __new__(cls, *args, **kwargs):  # 接收参数cls为Foo类,然后是f1 = Foo("Alex",age=32)里的name和age
        print("执行__new__方法", args, kwargs)
        ret = object.__new__(cls)  # 调用__new__生成一个Foo对象
        print(ret)                 # 打印 <__main__.Foo object at 0x000001AD868F8668>
        return ret                 # 返回生成的 Foo 对象

f1 = Foo("Alex",age=32)

"""
output:
执行__new__方法 ('Alex',) {'age': 32}
<__main__.Foo object at 0x000001B6523A64F0>
执行__init__方法
"""

 

6. __gt__、__lt__、__ge__、__le__:这几个都是用于比较大小的,我们可以对其进行重写,来自定义对象如何比较大小。它们的原型如下: 

    # 判断是否大于等于 greater than or equal,在obj >= other时调用
    def __ge__(self, *args, **kwargs):
        """ Return self >= value. """
        pass

    # 判断是否大于 greater than,在obj > other时调用
    def __gt__(self, *args, **kwargs):
        """ Return self > value. """
        pass

    # 判断是否小于等于 less than or equal,在obj <= other时调用
    def __le__(self, *args, **kwargs):
        """ Return self <= value. """
        pass

    # 判断是否小于 less than,在obj 
 

   下面举一个简单的例子:

class Car():
    def __init__(self, price):
        self.price = price

    def __lt__(self, other):
        print("execute __lt__")
        return self.price < other.price

c1 = Car(100)
c2 = Car(200)
if c1 < c2:
    print("car1 is cheaper.")
else:
    print("car2 is cheaper.")

  

7. __eq__和__hash__:__hash__实际上是返回一个int值(计算类中所有成员的hash值),用来唯一标记这个对象。户自定义类中,如果你没有实

   现__eq____hash__函数,那么class会继承到默认的__eq____hash__函数。

   先来解释下什么是可hash对象:如果一个对象是可哈希的,那么在它的生存期内必须不可变(需要一个哈希函数__hash__),而且可以和其他对象

   较(需要比较方法__eq__).相同的对象一定有相同的哈希值。

   1)不可hash:list, set, dict

   2)可hash:数值,字符串,boolean

   3)自定义类对象可不可hash:当类中只含可hash的成员时,该类定义的对象是可hash的。当我们实现的类想成为不可hash的类,则可以重写__eq__方法,

      然后不重写__hash__,__hash__方法会被置None,该类的对象就不可hash了。如果不重写__eq__,则会使用基类的实现,比较对象时会比较它们的hash值。

class Foo(object):
    def __init__(self):
        self.name = 'Alex'

    def __eq__(self, other):
        return self.name == other.name

f1 = Foo()
f2 = Foo()
print(f1 == f2)  # True
print(f1 is f2)  # False
print(hash(f1) == hash(f2))  # 抛出异常TypeError错误,因为此时__hash__=None

 

你可能感兴趣的:(object类)