2010-07-05 11 views
13

puedo definir un objeto y asignar atributos y métodos:objetos o cierres: ¿cuándo usarlos?

class object: 
    def __init__(self,a,b): 
     self.a = a 
     self.b = b 
    def add(self): 
     self.sum = self.a + self.b 
    def subtr(self): 
     self.fin = self.sum - self.b 
    def getpar(self): 
     return self.fin 

obj = object(2,3) 
obj.add() 
obj.subtr() 
obj.getpar() 

o proporcionar la misma funcionalidad mediante la definición de un cierre:

def closure(a,b): 
    par = {} 
    def add(): 
     par.update({'sum':a+b}) 
    def subtr(): 
     par.update({'fin':par['sum']-b}) 
    def getpar(): 
     return par['fin'] 
    return {'add':add,'subtr':subtr,'getpar':getpar} 

clos = closure(2,3) 
clos['add']() 
clos['subtr']() 
clos['getpar']() 

creo que la sintaxis de objetos se vería más limpio que la mayoría de los espectadores, pero ¿Hay casos en los que el uso de un cierre sería semánticamente preferible?

+1

Consulte también http://stackoverflow.com/questions/256625/when-to-use-closure/256651#256651. ;) – FMc

+1

:) Sí Stephen debería estudiar bajo Qc Na. – Yuji

+0

¿Todavía está tomando aprendices? :) – hatmatrix

Respuesta

7

En Python, los cierres pueden ser más difíciles de depurar y usar que los objetos más comunes (hay que guardar los callables en algún lugar, acceder a ellos con la notación ridícula clos['add'] etc., ...). Considere por ejemplo la imposibilidad de acceder al sum si encuentra algo extraño en el resultado ... depurar este tipo de cosas puede ser realmente difícil ;-)

La única ventaja compensadora real es la simplicidad, pero básicamente solo se aplica a casos realmente simples (para el momento en que tengas tres callables que son funciones internas, diría que estás al borde en ese sentido).

Tal la protección muy fuerte (mf protección de objetos 'por convención' para los objetos de clase e instancia), o la posible mayor familiaridad con los programadores de JavaScript, podría justificar el uso de cierres en lugar de clases e instancias en casos marginales, pero en la práctica, no me he encontrado en casos donde tales ventajas hipotéticas parecían aplicarse realmente, así que solo uso cierres en casos realmente simples ;-).

+0

verdad sobre mejor soporte de depuración para las clases ... – hatmatrix

+0

Si usa atributos de función en lugar de un diccionario, el cierre tiene el mismo uso que la clase. Escribiré una respuesta a continuación. – JDG

1

La sintaxis de llamada para la clase se ve mejor y usted puede crear clases de subclase. El cierre también implica repetir todos los nombres que desea exponer en la declaración return. Quizás eso está bien, aunque si quieres tener métodos realmente privados que estén más ocultos que la convención de prefijo de subrayado habitual

+0

sí, no hago subclase a menudo, pero ese es un argumento sólido para los objetos – hatmatrix

+0

Tengo curiosidad por su opinión sobre mi comentario a continuación, donde los atributos de función se utilizan para crear la misma sintaxis que se obtendría con un objeto más la conveniencia adicional de no (fácilmente) exponer las funciones internas a menos que lo incluyas explícitamente en la declaración de devolución. – JDG

15

Deberías usar la versión que exprese más claramente lo que estás tratando de lograr.

En el ejemplo dado, diría que la versión del objeto es más clara, ya que parece estar modelando un objeto con un estado que cambia. Al mirar el código que usa el valor, la versión del objeto parece expresar el intento claro, mientras que la versión de cierre parece tener operaciones (las cadenas de indexación y "magia") que están al lado del punto.

En Python, yo preferiría un enfoque basado en el cierre cuando lo que se necesita es algo que se asemeja más a una función, y tal vez necesite capturar algún estado.

def tag_closure(singular, plural): 
    def tag_it(n): 
     if n == 1: 
      return "1 " + singular 
     else: 
      return str(n) + " " + plural 
    return tag_it 

t_apple = tag_closure("apple", "apples") 
t_cherry = tag_closure("cherry", "cherries"); 
print t_apple(1), "and", t_cherry(15) 

Esta es quizás un poco más claro que el siguiente:

class tag_object(object): 
    def __init__(self, singular, plural): 
     self.singular = singular 
     self.plural = plural 

    def tag(self, n): 
     if n == 1: 
      return "1 " + self.singular 
     else: 
      return str(n) + " " + self.plural 

t_apple = tag_object("apple", "apples") 
t_cherry = tag_object("cherry", "cherries"); 
print t_apple.tag(1), "and", t_cherry.tag(15) 

Como regla general: si la cosa es en realidad sólo una única función, y sólo está capturando estado estático, y luego considerar un cierre. Si la cosa está destinada a tener un estado mutable, y/o tiene más de una función, use una clase.

Otra forma de decirlo: si está creando un error de cierre, esencialmente está duplicando la maquinaria de clase manualmente. Es mejor dejarlo en la construcción del lenguaje diseñada para hacerlo.

+2

+1 para enfatizar la legibilidad/claridad del código como un punto de decisión. – spade78

3

La única razón que puedo ver por el uso de cierres es, si se quiere una garantía bastante fuerte que el usuario de su objeto/cierre no tiene acceso a una variable oculta.

Algo como esto:

class Shotgun: 
    def __init__(self): 
     me = {} 
     me['ammo'] = 2 
     def shoot(): 
     if me['ammo']: 
      me['ammo'] -= 1 
      print "BANG" 
     else: 
      print "Click ..." 
     self.shoot = shoot 

s = Shotgun() 
s.shoot() 
s.shoot() 
s.shoot() 
+3

No estoy seguro de que podamos confiar en los cierres como una forma de hacer que las variables sean privadas. Uno podría actualizar 's = Shotgun()' con 's.shoot.func_closure [0] .cell_contents ['ammo'] = 1e20' – unutbu

+0

Tienes razón. Realmente no es una buena idea confiar en esto para cualquier seguridad. – phoku

+2

Cavar en un cierre suena menos directo que acceder a las partes internas de un objeto de clase usando la notación 'obj.variable =' al menos. – spade78

1

me hizo un comentario en el sentido de que el uso de la función de los atributos, un cierre puede utilizar la misma sintaxis que una clase porque las funciones son objetos en Python. Todas las variables internas también se vuelven accesibles al igual que el método de clase.

Tengo curiosidad si este enfoque hace cosas malas que no conozco.

def closure(a, b): 
    def add(): 
     closure.sum = a + b 
    def subtr(): 
     closure.fin = closure.sum - b 
    def getpar(): 
     return closure.fin 
    closure.add = add; 
    closure.subtr = subtr 
    closure.getpar = getpar 
    return closure 

clo = closure(2,3) 
clo.add() 
clo.subtr() 
print(clo.getpar()) 
print(clo.sum) 
print(clo.fin) 
Cuestiones relacionadas