Pregunta ¿Identificando que una variable es una clase de estilo nuevo en Python?


Estoy usando Python 2.x y me pregunto si hay una manera de decir si una variable es una clase de estilo nuevo. Sé que si se trata de una clase de estilo antiguo, puedo hacer lo siguiente para averiguarlo.

import types

class oldclass:
  pass

def test():
  o = oldclass()
  if type(o) is types.InstanceType:
    print 'Is old-style'
  else:
    print 'Is NOT old-style'

Pero no he podido encontrar nada que funcione para las clases de nuevo estilo. encontré esta pregunta, pero las soluciones propuestas no parecen funcionar como se esperaba, porque los valores simples se identifican como clases.

import inspect

def newclass(object):
  pass

def test():
  n = newclass()
  if inspect.isclass(n):
    print 'Is class'
  else:
    print 'Is NOT class'
  if inspect.isclass(type(n)):
    print 'Is class'
  else:
    print 'Is NOT class'
  if inspect.isclass(type(1)):
    print 'Is class'
  else:
    print 'Is NOT class'
  if isinstance(n, object):
    print 'Is class'
  else:
    print 'Is NOT class'
  if isinstance(1, object):
    print 'Is class'
  else:
    print 'Is NOT class'

Entonces, ¿hay alguna forma de hacer algo como esto? ¿O todo en Python es solo una clase y no hay forma de evitarlo?


12
2018-04-16 16:33


origen


Respuestas:


Creo que lo que estás preguntando es: "¿Puedo probar si una clase se definió en código Python como una clase de estilo nuevo?". Técnicamente simples tipos como int  son nuevas clases de estilo, pero aún es posible distinguir las clases escritas en Python de los tipos incorporados.

Aquí hay algo que funciona, aunque es un poco complicado:

def is_new_style(cls):
    return hasattr(cls, '__class__') \
           and \
           ('__dict__' in dir(cls) or hasattr(cls, '__slots__'))


class new_style(object):
    pass

class old_style():
    pass

print is_new_style(int)
print is_new_style(new_style)
print is_new_style(old_style)

Salida de Python 2.6:

False
True
False

Aquí hay una manera diferente de hacerlo:

def is_new_style(cls):
    return str(cls).startswith('<class ')

7
2018-04-16 17:01



Yo creo que esto es suficiente

def is_new_style_class(klass):
    return issubclass(klass, object)

def is_new_style_class_instance(instance):
    return issubclass(instance.__class__, object)

Por lo general, solo necesitas el is_new_style_class función para sus propósitos. Todo lo que no sea una clase arrojará una TypeError, por lo que es posible que desee actualizarlo a:

def is_new_style_class(klass):
    try:
        return issubclass(klass, object)
    except TypeError:
        return False

Ejemplos:

>>> class New(object): pass
... 
>>> is_new_style_class(New)
True
>>> class Old: pass
... 
>>> is_new_style_class(Old)
False
>>> is_new_style_class(1)
False
>>> is_new_style_class(int)
True

int, al ser un tipo, es por definición una clase de nuevo estilo (ver Unificar tipos y clases en Python 2.2 ), o -si prefieres- las clases de nuevo estilo son por definición tipos.


1
2018-04-16 19:33



No es que "todo sea una clase": con lo que te encuentras es que "todo es un objeto"(es decir, cada cosa (de nuevo estilo) desciende de" objeto ").

Pero las clases de nuevo estilo son en sí mismas un "tipo" (en realidad, se introdujeron para reunir clases y tipos). Así que puedes intentar buscar

import types

type(o) == types.TypeType

¿Eso resuelve tu problema?


1
2018-04-16 16:57



Verificar las clases antiguas es realmente fácil. Sólo revisa type(cls) is types.ClassType. Verificar las clases de nuevo estilo también es fácil, isinstance(cls, type). Tenga en cuenta que los tipos incorporados también son clases de estilo nuevo.

Parece que no hay una forma trivial de distinguir las incorporaciones de las clases escritas en Python. Las clases de estilo nuevo con __slots__ tampoco tienen __dict__, al igual que int o str. Comprobar si str (cls) coincide con el patrón esperado falla si la metaclase de las clases prevalece sobre el método __str__. Algunas otras formas que tampoco funcionan:

  • cls.__module__ == '__builtin__' (puedes reasignar __module__ en las clases)
  • not any(value is cls for value in vars(__builtins__).values()) (puede agregar cosas al módulo __builtin__).

El hecho de que la unificación de tipos incorporados y definidos por el usuario es tan buena que distinguirlos no es un problema trivial debería implicar para usted el punto subyacente. Realmente no deberías tener que distinguir entre ellos. No importa cuál sea el objeto si implementa el protocolo esperado.


-1
2018-04-16 20:38