Question

Disons que je déclare une classe C et que certaines déclarations sont très similaires. J'aimerais utiliser une fonction f pour réduire la répétition de code pour ces déclarations. Il est possible de simplement déclarer et utiliser f comme d'habitude:

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     w = f(42)
... 
>>> C.v
'<9>'
>>> C.w
'<42>'
>>> C.f(4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method f() must be called with C instance as first argument (got int instance instead)

Oups! J'ai par inadvertance exposé f au monde extérieur, mais cela ne nécessite pas d'argument self (et ne peut pas pour des raisons évidentes). Une possibilité serait de supprimer la fonction après mon utilisation:

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     del f
... 
>>> C.v
'<9>'
>>> C.f
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'C' has no attribute 'f'

Mais que faire si je veux utiliser f plus tard, après la déclaration? Il ne faut pas supprimer la fonction. Je pourrais le rendre "privé". (c.-à-d. préfixez son nom avec __ ) et donnez-lui le traitement @staticmethod , mais appeler des objets staticmethod par des canaux anormaux devient très funky:

>>> class C(object):
...     @staticmethod
...     def __f(num):
...             return '<' + str(num) + '>'
...     v = __f.__get__(1)(9)   # argument to __get__ is ignored...
... 
>>> C.v
'<9>'

Je dois utiliser la folie ci-dessus car les objets staticmethod , qui sont des descripteurs, ne sont pas eux-mêmes appelables. Je dois récupérer la fonction entourée par l'objet staticmethod avant de pouvoir l'appeler.

Il doit y avoir un meilleur moyen de le faire. Comment puis-je déclarer proprement une fonction dans une classe, l'utiliser lors de sa déclaration et l'utiliser ultérieurement dans la classe? Devrais-je même faire cela?

Était-ce utile?

La solution

Tout simplement, la solution est que f n’a pas besoin d’être membre de la classe. Je suppose que votre processus de pensée est passé par un filtre de la langue javaish qui est à l'origine du blocage mental. Cela ressemble un peu à ceci:

def f(n):
    return '<' + str(num) + '>'

class C(object):

    v = f(9)
    w = f(42)

Ensuite, lorsque vous souhaitez utiliser f à nouveau, utilisez-le simplement

>>> f(4)
'<4>'

Je pense que la morale du conte est "En Python, vous n'avez pas à forcer tout dans une classe".

Autres conseils

Extension de Ali A la réponse, si vous voulez vraiment éviter f dans l'espace de nommage du module (et utiliser un nom non exporté tel que _f, ou définir __all__ n'est pas suffisant), alors vous pouvez y parvenir en créant la classe dans une fermeture.

def create_C():
    def f(num):
        return '<' + str(num) + '>'

    class C(object):
        v = f(9)
        def method_using_f(self, x):  return f(x*2)
    return C

C=create_C()
del create_C

De cette façon, C a accès à f dans sa définition et ses méthodes, mais rien d’autre n’y a accès (sauf pour une introspection assez impliquée de ses méthodes ( C.method_using_f.im_func.func_closure ))

C’est probablement exagéré dans la plupart des cas - documentant que f est interne en utilisant le paramètre "_". convention de nommage préfixe devrait généralement suffisant.

[Éditer] Une autre option consiste à conserver une référence à l'objet fonction pré-encapsulée dans les méthodes pour lesquelles vous souhaitez l'utiliser. Par exemple, en le définissant comme argument par défaut:

class C(object):
    def f(num):
        return '<' + str(num) + '>'

    v = f(9)
    def method_using_f(self, x, f=f):  return f(x*2)

    del f

(Bien que je pense que l'approche de la fermeture est probablement meilleure)

C’est une possibilité:

class _C:
    # Do most of the function definitions in here
    @classmethod
    def f(cls):
        return 'boo'

class C(_C):
    # Do the subsequent decoration in here
    v = _C.f()

Je crois que vous essayez de faire ceci:

class C():
...     class F():
...         def __call__(self,num):
...             return "<"+str(num)+">"
...     f=F()
...     v=f(9)
>>> C.v
'<9>'
>>> C.f(25)
'<25>'
>>> 

Peut-être y at-il une solution meilleure ou plus pythonique ...

  

"déclarez une fonction dans une classe, utilisez-la lors de sa déclaration, puis utilisez-la ultérieurement à partir de la classe"

     

Désolé. Ne peut être fait.

"Je ne peux pas le faire". ne semble pas bien s'entendre avec Python

Une option: écrire un meilleur méthode statique :

class staticfunc(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kw):
        return self.func(*args, **kw)
    def __repr__(self):
        return 'staticfunc(%r)' % self.func

Commençons par le début.

"déclarez une fonction dans une classe, utilisez-la lors de sa déclaration, puis utilisez-la ultérieurement à partir de la classe"

.

Désolé. Ne peut pas être fait. " Dans une classe " contredit "utilisé lors de la déclaration".

  • Dans une classe, un moyen créé dans le cadre de la déclaration.
  • Utilisé lors de la déclaration signifie qu'il existe en dehors de la classe. Souvent en méta classe. Cependant, il existe d'autres moyens.

On ne sait pas ce que sont censés être C.w et C.v. Sont-ils juste des chaînes? Si tel est le cas, une fonction externe f est la meilleure solution. Le " pas encombrer l'espace de noms " est un peu spécieux. Après tout, vous souhaitez l’utiliser à nouveau.

Il est dans le même module que C. C’est pourquoi Python a des modules. Il lie la fonction et la classe ensemble.

import myCmod

myCmod.C.w
myCmod.C.v
myCmod.f(42)

Si w et v ne sont pas des chaînes simples, il existe une très bonne solution offrant beaucoup de flexibilité.

En règle générale, vous pouvez utiliser d'autres classes pour les variables de niveau classe ("statiques"). Il n’est pas possible de réaliser complètement l’API souhaitée, mais c’est proche.

>>> class F(object):
    def __init__( self, num ):
        self.value= num
        self.format= "<%d>" % ( num, )

>>> class C(object):
    w= F(42)
    v= F(9)

>>> C.w
<__main__.F object at 0x00C58C30>
>>> C.w.format
'<42>'
>>> C.v.format
'<9>'

L’avantage de cela est que F est une solution de premier ordre qui peut être étendue. Pas un " caché " chose que nous essayons d'éviter d'exposer. C’est une réalité, alors nous pourrions aussi bien suivre le principe Ouvert / Fermé et le rendre ouvert à l’extension.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top