2009-11-19 3 views
0

(Ce qui suit est liée python3 (si cette matière).)len (objet) ou hasattr (objet, __iter__)?

Ce code ce que j'ai écrit (simplifié):

class MyClass: 

    def __init__(self): 
     self.__some_var = [] 

    @property 
    def some_var(self): 
     return self.__some__var 

    @some_var.setter 
    def some_var(self, new_value): 
     if hasattr(new_value, '__iter__'): 
      self.__some_var = new_value 
     else: 
      self.__some_var.append(new_value) 

Je veux remplacer lors de la configuration si leur est plusieurs "valeurs" (c'est-à-dire si new_value est une itérable de, dans mon cas, des objets non-iterable) et ajoutant si leur est seulement une "valeur". Je suis préoccupé par la performance de hasattr donc je me demande si je ne devrais pas utiliser ce compositeur à la place:

@some_var.setter 
    def some_var(self, *args): 
     if len(args) > 1: 
      self.__some_var = args 
     else: 
      self.__some_var.append(args) 

Merci pour votre attention!

+0

Une optimisation prématurée? Faites un simple benchmark et voyez si la différence est même mesurable. Si quoi que ce soit, je m'attends à 'hasattr' être plus rapide. – intgr

+0

@thomas, dans votre première forme, êtes-vous ** sûr ** que vous voulez "remplacer" quand 'new_value' est, disons,' 'thomas" '? Les chaînes ont '__iter__', et sont des séquences, mais presque invariablement dans le code, nous voulons les traiter comme des scalaires à la place. (La seconde forme a une sémantique radicalement différente, bien sûr, donc elle sera toujours "remplacer", même lorsqu'elle est appelée avec une liste). –

+0

En fait, leur un test juste avant l'affectation si l'élément values ​​() de new_value a une méthode, vous pouvez juste passer un objet qui se comporte spécifiquement à cette fonction, ou bien déclencher une erreur. – thomas

Répondre

4

Il n'y a pas de «coût de performance» de hasattr qui compte. C'est assez rapide pour que vous ayez du mal à le mesurer.

Veuillez ne pas utiliser __ (double trait de soulignement) pour vos propres attributs. C'est déroutant pour le reste d'entre nous.

Il est généralement préférable d'utiliser l'appartenance à la classe collections Abstract Base Class pour ce genre de chose. Cela vous donne quelque chose qui fonctionnera probablement mieux car il exprime la sémantique un peu plus clairement.

+0

Je crois, et je pourrais mal comprendre, que isinstance est une mauvaise pratique en général, et que la façon de Python est de dactylographie. En outre, j'ai eu une fois des problèmes avec isinstance et issubclass juste à cause de l'importation différente, donc je préfère les éviter. – thomas

+0

Ho et je vais éviter __ dans le futur, merci :) – thomas

+1

Dans votre cas, vous devez savoir si c'est une collection ou non. len ('aaa')> 1 aussi. –

0

En termes d'efficacité:

  • hasattr() aurait un pire cas de O (1) (constante). Append() est aussi le pire des cas de O (1) (constante).
+1

Je soupçonne une petite confusion. Hasattr est en principe une recherche dict (ou plus d'un), donc c'est 'O (1)'. – u0b34a0f6ae

+0

@ kaizer.se right - Je pensais que toute la liste était inspectée pour voir si un élément était déjà dans la liste. Ce serait O (n) dans le pire des cas si l'élément n'était pas dans la liste, ou s'il était à la fin de la liste. J'ai relu le code, et ce qu'il fait est de vérifier si new_value est une collection elle-même. Cela a plus de sens maintenant. –

2

Une alternative pourrait être le canard en tapant:

Ici, je suppose que vous voulez évaluer (= faire une liste) de la itératives, car il pourrait être un itérateur que vous devez développer immédiatement pour sauver.

@some_var.setter 
def some_var(self, new_value): 
    try: 
     self.__some_var = list(new_value) 
    except TypeError: 
     self.__some_var.append(new_value) 

Ici nous nous attendons à list() de lever ValueError si new_value n'est pas itérable. En réponse à votre commentaire sur la réponse de S.Lott, je ne pense pas que l'utilisation de hasattr soit vraiment un style de frappe de canard.

+0

L'expansion de l'itérable est une très mauvaise pratique. – smci