Creo que este es un ejemplo un poco engañoso; hay algo que no has declarado. Supongo que cuando dices que "tienes una interfaz", lo que quieres decir es que tienes un código que acepta un objeto y llama a su método run
.
Si no está probando el tipo de ese objeto antes de llamar a su método run
, ¡está utilizando el tipo de pato, simple y llanamente! (En este caso, si tiene un método run
, entonces es un Runner
.) Mientras no uses type
o isinstance
en el objeto con un método run
, entonces estarás siendo Pythonic.
La cuestión de si debe aceptar strings simples o solo objetos de nodo es una pregunta sutilmente diferente. ¡Las cadenas y los objetos node
probablemente no implementan la misma interfaz en absoluto! Las cadenas fundamentalmente no codifican como node
, por lo que no es necesario tratarlas como tal. Esto es como un elefante que aparece, y si quieres que grazné como un pato, debes darle al elefante un reproductor de cintas y entrenar al elefante para que lo use primero.
Así que esto ya no es una cuestión de "tipa pato", sino de diseño de interfaz. Estás tratando de decidir qué tan estricto quieres que sea tu interfaz.
Para darle una respuesta, entonces, en este nivel, creo que es más pitónico suponer que run
devuelve un objeto node
. No es necesario utilizar isinstance
o type
para probarlo. Simplemente pretenda que es un objeto node
y si el programador que usa su interfaz se equivoca y ve una excepción, entonces tendrán que leer su docstring, que les dirá que run
debe pasar un objeto node
.
Luego, si quiere para aceptar cadenas, o cosas que graznan como cadenas, puede hacerlo. Y como las cadenas son tipos bastante primitivos, diría que no es inapropiado usar isinstance(obj, basestring)
(pero notype(obj) == str
porque eso rechaza las cadenas de unicode, etc.). Básicamente, esto es que eres muy liberal y amable con los usuarios perezosos de tu programa; ya vas más allá aceptando elefantes y cosas que graznan como patos.
(Más concretamente, yo diría que esto es un poco como llamar iter
en un argumento al comienzo de una función que desea aceptar ambos generadores y secuencias.)
Estoy un poco confundido. ¿Estás hablando del valor pasado a 'ejecutar' (a través de' arg')? ¿O está hablando de cómo manejar el valor hipotético devuelto por el método 'run' de un objeto que implementa la interfaz' Runner'? – senderle
Me refiero a la devolución. He editado el 'arg' para que no distraiga (gracias por señalar esto). – Owen