type(obj) 和 obj.__class__ 之间的区别

发布于 2024-07-26 12:52:16 字数 300 浏览 2 评论 0原文

type(obj)obj.__class__ 有什么区别? 是否有可能 type(obj) 不是 obj.__class__

我想编写一个对所提供的对象通用的函数,使用与另一个参数相同类型的默认值 1。 下面的#1 或#2 哪种变体会做正确的事情?

def f(a, b=None):
  if b is None:
    b = type(a)(1) # #1
    b = a.__class__(1) # #2

What is the difference between type(obj) and obj.__class__? Is there ever a possibility of type(obj) is not obj.__class__?

I want to write a function that works generically on the supplied objects, using a default value of 1 in the same type as another parameter. Which variation, #1 or #2 below, is going to do the right thing?

def f(a, b=None):
  if b is None:
    b = type(a)(1) # #1
    b = a.__class__(1) # #2

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

秋千易 2024-08-02 12:52:16

这是一个老问题,但似乎没有一个答案提到这一点。 在一般情况下,新样式类可能有不同的type(instance)instance.__class__

class ClassA(object):
    def display(self):
        print("ClassA")

class ClassB(object):
    __class__ = ClassA

    def display(self):
        print("ClassB")

instance = ClassB()

print(type(instance))
print(instance.__class__)
instance.display()

: :

<class '__main__.ClassB'>
<class '__main__.ClassA'>
ClassB

原因是 ClassB 覆盖了 __class__ 描述符,但对象中的内部类型字段并未更改。 type(instance) 直接从该类型字段读取,因此它返回正确的值,而 instance.__class__ 指的是新的描述符替换 Python 提供的原始描述符,这读取内部类型字段。 它不读取该内部类型字段,而是返回一个硬编码值。

This is an old question, but none of the answers seems to mention that. in the general case, it IS possible for a new-style class to have different values for type(instance) and instance.__class__:

class ClassA(object):
    def display(self):
        print("ClassA")

class ClassB(object):
    __class__ = ClassA

    def display(self):
        print("ClassB")

instance = ClassB()

print(type(instance))
print(instance.__class__)
instance.display()

Output:

<class '__main__.ClassB'>
<class '__main__.ClassA'>
ClassB

The reason is that ClassB is overriding the __class__ descriptor, however the internal type field in the object is not changed. type(instance) reads directly from that type field, so it returns the correct value, whereas instance.__class__ refers to the new descriptor replacing the original descriptor provided by Python, which reads the internal type field. Instead of reading that internal type field, it returns a hardcoded value.

厌倦 2024-08-02 12:52:16

旧式类是问题所在,叹息:

>>> class old: pass
... 
>>> x=old()
>>> type(x)
<type 'instance'>
>>> x.__class__
<class __main__.old at 0x6a150>
>>> 

在 Python 3 中不是问题,因为现在所有类都是新式的;-)。

在Python 2中,只有当一个类继承自另一个新式类(包括object和各种内置类型,例如dict>listset、...) 或隐式或显式将 __metaclass__ 设置为 type

Old-style classes are the problem, sigh:

>>> class old: pass
... 
>>> x=old()
>>> type(x)
<type 'instance'>
>>> x.__class__
<class __main__.old at 0x6a150>
>>> 

Not a problem in Python 3 since all classes are new-style now;-).

In Python 2, a class is new-style only if it inherits from another new-style class (including object and the various built-in types such as dict, list, set, ...) or implicitly or explicitly sets __metaclass__ to type.

不必你懂 2024-08-02 12:52:16

对于 Python 2 中的旧样式类,type(obj)type.__class__ 的行为不同:

>>> class a(object):
...     pass
... 
>>> class b(a):
...     pass
... 
>>> class c:
...     pass
... 
>>> ai = a()
>>> bi = b()
>>> ci = c()
>>> type(ai) is ai.__class__
True
>>> type(bi) is bi.__class__
True
>>> type(ci) is ci.__class__
False
>>> type(ci)
<type 'instance'>
>>> ci.__class__
<class __main__.c at 0x7f437cee8600>

对此进行了解释 文档中

对于旧式类,语句 x.__class__ 提供 x 的类,但 type(x) 始终为 <代码><输入“实例”>。 这反映了这样一个事实:所有旧式实例(与其类无关)都是使用单个内置类型(称为实例)实现的。

type(obj) and type.__class__ do not behave the same for old style classes in Python 2:

>>> class a(object):
...     pass
... 
>>> class b(a):
...     pass
... 
>>> class c:
...     pass
... 
>>> ai = a()
>>> bi = b()
>>> ci = c()
>>> type(ai) is ai.__class__
True
>>> type(bi) is bi.__class__
True
>>> type(ci) is ci.__class__
False
>>> type(ci)
<type 'instance'>
>>> ci.__class__
<class __main__.c at 0x7f437cee8600>

This is explained in the documentation:

For an old-style class, the statement x.__class__ provides the class of x, but type(x) is always <type 'instance'>. This reflects the fact that all old-style instances, independent of their class, are implemented with a single built-in type, called instance.

属性 2024-08-02 12:52:16

代理对象(使用弱引用)有一个有趣的边缘情况:

>>> import weakref
>>> class MyClass:
...     x = 42
... 
>>> obj = MyClass()
>>> obj_proxy = weakref.proxy(obj)
>>> obj_proxy.x  # proxies attribute lookup to the referenced object
42
>>> type(obj_proxy)  # returns type of the proxy 
weakproxy
>>> obj_proxy.__class__  # returns type of the referenced object
__main__.MyClass
>>> del obj  # breaks the proxy's weak reference
>>> type(obj_proxy)  # still works
weakproxy
>>> obj_proxy.__class__  # fails
ReferenceError: weakly-referenced object no longer exists

There's an interesting edge case with proxy objects (that use weak references):

>>> import weakref
>>> class MyClass:
...     x = 42
... 
>>> obj = MyClass()
>>> obj_proxy = weakref.proxy(obj)
>>> obj_proxy.x  # proxies attribute lookup to the referenced object
42
>>> type(obj_proxy)  # returns type of the proxy 
weakproxy
>>> obj_proxy.__class__  # returns type of the referenced object
__main__.MyClass
>>> del obj  # breaks the proxy's weak reference
>>> type(obj_proxy)  # still works
weakproxy
>>> obj_proxy.__class__  # fails
ReferenceError: weakly-referenced object no longer exists
半衾梦 2024-08-02 12:52:16

仅供参考 - Django 就是这样做的。

>>> from django.core.files.storage import default_storage
>>> type(default_storage)
django.core.files.storage.DefaultStorage
>>> default_storage.__class__
django.core.files.storage.FileSystemStorage

作为一个认知能力有限的人,只是想弄清楚正在发生什么才能完成工作……这是令人沮丧的。

FYI - Django does this.

>>> from django.core.files.storage import default_storage
>>> type(default_storage)
django.core.files.storage.DefaultStorage
>>> default_storage.__class__
django.core.files.storage.FileSystemStorage

As someone with finite cognitive capacity who's just trying to figure out what's going in order to get work done... it's frustrating.

以为你会在 2024-08-02 12:52:16

这将使您更好地理解差异:
概括:
classA.one、self.class.one 和 type(obj).one 是相同的。
self.one 和 obj.one 是相同的,并且它们在每个实例中都是不同的。

class classA:

    one = "One"

    def __init__(self, val):
        self.__class__.one = val

    def show(self, marker):
        print("{}: self.one= {}, self.__class__.one= {}, classA.one= {}, type(self).one = {}".format(marker, self.one, self.__class__.one, classA.one, type(self).one))


one = classA('A')

one.show('One')

two = classA('B')
two.one = 'C'

two.show('Two')
print("{}".format(type(two).one))

three = classA('C')
classA.one = 'D'
three.one = 'E'
three.__class__.one = 'F'
three.show('Three')
two.show('Two')
one.show('One')
One: self.one= A, self.__class__.one= A, classA.one= A, type(self).one = A
Two: self.one= C, self.__class__.one= B, classA.one= B, type(self).one = B
B
Three: self.one= E, self.__class__.one= F, classA.one= F, type(self).one = F
Two: self.one= C, self.__class__.one= F, classA.one= F, type(self).one = F
One: self.one= F, self.__class__.one= F, classA.one= F, type(self).one = F

This will give you a more understanding of the differences:
Summary:
classA.one, self.class.one and type(obj).one are the same.
self.one and obj.one are the same and they are distinct per instance.

class classA:

    one = "One"

    def __init__(self, val):
        self.__class__.one = val

    def show(self, marker):
        print("{}: self.one= {}, self.__class__.one= {}, classA.one= {}, type(self).one = {}".format(marker, self.one, self.__class__.one, classA.one, type(self).one))


one = classA('A')

one.show('One')

two = classA('B')
two.one = 'C'

two.show('Two')
print("{}".format(type(two).one))

three = classA('C')
classA.one = 'D'
three.one = 'E'
three.__class__.one = 'F'
three.show('Three')
two.show('Two')
one.show('One')
One: self.one= A, self.__class__.one= A, classA.one= A, type(self).one = A
Two: self.one= C, self.__class__.one= B, classA.one= B, type(self).one = B
B
Three: self.one= E, self.__class__.one= F, classA.one= F, type(self).one = F
Two: self.one= C, self.__class__.one= F, classA.one= F, type(self).one = F
One: self.one= F, self.__class__.one= F, classA.one= F, type(self).one = F

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文