Yo diría que el número uno está tratando de escribir código estáticamente tipado en un lenguaje dinámico.
no dude en utilizar un identificador para apuntar a una cadena y luego una lista de secciones independientes de código
keys = 'foo bar foobar' # Imagine this coming in as an argument
keys = keys.split() # Now the semantically chose name for the argument can be
# reused As the semantically chosen name for a local variable
no dude en tratar funciones como valores normales: son. Toma el siguiente analizador Supongamos que queremos tratar todas las etiquetas de encabezado por igual y las etiquetas ul como las etiquetas ol.
class Parser(HTMLParser):
def __init__(self, html):
self.feed(html)
def handle_starttag(self, tag, attrs):
parse_method = 'parse_' + tag
if hasattr(self, parse_method):
getattr(self, parse_method)(attrs)
def parse_list(self, attrs):
# generic code
def parse_header(self, attrs):
# more generic code
parse_h1 = parse_h2 = parse_h3 = parse_h4 = parse_h5 = parse_h6 = parse_header
parse_ol = parse_ul = parse_list
Esto podría hacerse mediante el uso de código de menos genérico en el método handle_starttag
en un lenguaje como Java llevando un registro de qué etiquetas mapa para el mismo método pero si luego decide que desea manejar etiquetas div, se tiene que agregar eso en la lógica de despacho. Aquí solo agrega el método parse_div
y listo.
No tipear! ¡Tipo de pato!
def funtion(arg):
if hasattr(arg, 'attr1') and hasattr(arg, 'attr2'):
foo(arg):
else:
raise TypeError("arg must have 'attr1' and 'attr2'")
a diferencia del isinstance(arg, Foo)
. Esto le permite pasar cualquier objeto con attr1
y attr2
. Esto le permite, por ejemplo, pasar una clase de seguimiento envuelta alrededor de un objeto para fines de depuración. Tendría que modificar la clase para hacer eso en Java AFAIK.
Como lo señala THC4k, otra forma (más pitonica) de hacer esto es la expresión EAPF. No me gusta esto porque me gusta detectar errores tan pronto como sea posible. Sin embargo, es más eficiente si esperas que el código rara vez falle. No le digas a nadie que no me gusta, aunque nuestros dejarán de pensar que sé cómo escribir Python. Aquí hay un ejemplo cortesía de THC4k.
try:
foo(arg):
except (AttributeError, TypeError):
raise InvalidArgumentError(foo, arg)
Es un volado que si debemos coger el AttributeError
y TypeError
o simplemente dejar que se propagan a alguna parte que sabe cómo manejar ellos, pero esto es sólo un ejemplo así que vamos a dejarlo volar.
@ THC4k. ¿Cómo se dice que es extraño? A menos que 'type (Foo)' sea una subclase de 'type' que sobrepase el atributo' __instancecheck__', 'isinstance' depende de la ubicación en las jerarquías de clase. La forma en que presenté no comparte esta deficiencia. LBYL vs EAFP es otro problema. Olvidé incluir el otro estilo. – aaronasterling
'if hasattr (arg, 'attr1') y hasattr (arg, 'attr2')' es una verificación de tipo. Comprueba si arg pertenece a la clase de tipos (implícita) de "cosas que tienen un atributo attr1 y attr2". Ese * es * más general que el uso de 'isinstance', que solo busca un tipo único, no una clase de tipo completa. Pero esos controles a menudo son innecesarios: simplemente haga foo (arg) de inmediato, vea qué sucede y capture Excepciones donde tenga sentido. Deje que Python le haga todas las comprobaciones de tipos - si foo (arg) no tiene sentido, arrojará una excepción eventualmente. –
@aaronasterling lo siento, sí mala redacción, estaba reescribiendo el comentario. –