web-dev-qa-db-fra.com

Comment fonctionne le décorateur @property?

Je voudrais comprendre comment fonctionne la fonction intégrée property. Ce qui me trouble, c'est que property peut également être utilisé en tant que décorateur, mais il ne prend que des arguments lorsqu'il est utilisé en tant que fonction intégrée et non en tant que décorateur.

Cet exemple provient de documentation :

class C(object):
    def __init__(self):
        self._x = None

    def getx(self):
        return self._x
    def setx(self, value):
        self._x = value
    def delx(self):
        del self._x
    x = property(getx, setx, delx, "I'm the 'x' property.")

Les arguments de property sont getx, setx, delx et une chaîne de documentation.

Dans le code ci-dessous, property est utilisé comme décorateur. L'objet en est la fonction x, mais dans le code ci-dessus, il n'y a pas de place pour une fonction d'objet dans les arguments.

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

Et comment les décorateurs x.setter et x.deleter sont-ils créés? Je suis confus.

745
ashim

La fonction property() renvoie un spécial objet descripteur :

>>> property()
<property object at 0x10ff07940>

C'est cet objet qui a des méthodes extra :

>>> property().getter
<built-in method getter of property object at 0x10ff07998>
>>> property().setter
<built-in method setter of property object at 0x10ff07940>
>>> property().deleter
<built-in method deleter of property object at 0x10ff07998>

Ceux-ci agissent en tant que décorateurs aussi . Ils renvoient un nouvel objet de propriété:

>>> property().getter(None)
<property object at 0x10ff079f0>

c'est une copie de l'ancien objet, mais avec l'une des fonctions remplacées.

Rappelez-vous que la syntaxe @decorator n'est qu'un sucre syntaxique; la syntaxe:

@property
def foo(self): return self._foo

signifie vraiment la même chose que

def foo(self): return self._foo
foo = property(foo)

donc foo la fonction est remplacée par property(foo), ce que nous avons vu ci-dessus est un objet spécial. Ensuite, lorsque vous utilisez @foo.setter(), vous appelez la méthode property().setter que je vous ai vue ci-dessus, qui renvoie une nouvelle copie de la propriété, mais cette fois avec la fonction setter remplacée par la méthode décorée.

La séquence suivante crée également une propriété complète, en utilisant ces méthodes de décorateur.

Nous créons d’abord quelques fonctions et un objet property avec juste un getter:

>>> def getter(self): print 'Get!'
... 
>>> def setter(self, value): print 'Set to {!r}!'.format(value)
... 
>>> def deleter(self): print 'Delete!'
... 
>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True

Ensuite, nous utilisons la méthode .setter() pour ajouter un configurateur:

>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True

Enfin, nous ajoutons un deleter avec la méthode .deleter():

>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True

Dernier point mais non le moindre, l’objet property agit comme un objet descripteur , donc il a .__get__() , .__set__() et .__delete__() méthodes à connecter à un attribut d'instance pour obtenir, définir et supprimer:

>>> class Foo(object): pass
... 
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!

Le Descriptor Howto inclut un exemple de pure python implémentation du type property():

class Property(object):
    "Emulate PyProperty_Type() in Objects/descrobject.c"

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)
894
Martijn Pieters

La documentation indique qu’il s’agit d’un raccourci pour la création de propriétés en lecture seule. Alors

@property
def x(self):
    return self._x

est équivalent à

def getx(self):
    return self._x
x = property(getx)
121
J0HN

La première partie est simple:

@property
def x(self): ...

est le même que

def x(self): ...
x = property(x)
  • qui, à son tour, est la syntaxe simplifiée permettant de créer une property avec seulement un getter.

La prochaine étape consisterait à étendre cette propriété avec un séparateur et un séparateur. Et cela se produit avec les méthodes appropriées:

@x.setter
def x(self, value): ...

retourne une nouvelle propriété qui hérite de tout de l'ancienne x et du séparateur donné.

x.deleter fonctionne de la même manière.

71
glglgl

Voici un exemple minimal de la façon dont @property peut être implémenté:

class Thing:
    def __init__(self, my_Word):
        self._Word = my_Word 
    @property
    def Word(self):
        return self._Word

>>> print( Thing('ok').Word )
'ok'

Sinon, Word reste une méthode au lieu d'une propriété.

class Thing:
    def __init__(self, my_Word):
        self._Word = my_Word
    def Word(self):
        return self._Word

>>> print( Thing('ok').Word() )
'ok'
64
AlexG

Ce qui suit:

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

Est le même que:

class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, _x_set, _x_del, 
                    "I'm the 'x' property.")

Est le même que:

class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, doc="I'm the 'x' property.")
    x = x.setter(_x_set)
    x = x.deleter(_x_del)

Est le même que:

class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x
    x = property(_x_get, doc="I'm the 'x' property.")

    def _x_set(self, value):
        self._x = value
    x = x.setter(_x_set)

    def _x_del(self):
        del self._x
    x = x.deleter(_x_del)

Quel est le même que:

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x
34
Bill Moore

Voici un autre exemple sur la façon dont @property peut aider quand on doit refactoriser le code extrait de ici (je ne le résume que ci-dessous):

Imaginez que vous avez créé une classe Money comme ceci:

class Money:
    def __init__(self, dollars, cents):
        self.dollars = dollars
        self.cents = cents

et un utilisateur crée une bibliothèque en fonction de cette classe où il utilise, par exemple.

money = Money(27, 12)

print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 27 dollar and 12 cents.

Supposons maintenant que vous décidiez de changer votre classe Money et de vous débarrasser des attributs dollars et cents, mais que vous décidiez plutôt de ne suivre que le montant total des cents:

class Money:
    def __init__(self, dollars, cents):
        self.total_cents = dollars * 100 + cents

Si l'utilisateur mentionné ci-dessus essaie maintenant de faire fonctionner sa bibliothèque comme auparavant

money = Money(27, 12)

print("I have {} dollar and {} cents.".format(money.dollars, money.cents))

il en résultera une erreur

AttributeError: l'objet 'Money' n'a pas d'attribut 'dollars'

Cela signifie que désormais, toute personne qui s'appuie sur votre classe Money d'origine devrait modifier toutes les lignes de code où dollars et cents sont utilisés, ce qui peut être très pénible ... Alors, comment pourrait-on éviter cela? En utilisant @property

Voilà comment:

class Money:
    def __init__(self, dollars, cents):
        self.total_cents = dollars * 100 + cents

    # Getter and setter for dollars...
    @property
    def dollars(self):
        return self.total_cents // 100

    @dollars.setter
    def dollars(self, new_dollars):
        self.total_cents = 100 * new_dollars + self.cents

    # And the getter and setter for cents.
    @property
    def cents(self):
        return self.total_cents % 100

    @cents.setter
    def cents(self, new_cents):
        self.total_cents = 100 * self.dollars + new_cents

quand nous appelons maintenant de notre bibliothèque

money = Money(27, 12)

print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 27 dollar and 12 cents.

cela fonctionnera comme prévu et nous n'avons pas eu à changer une seule ligne de code dans notre bibliothèque! En fait, nous n'aurions même pas besoin de savoir que la bibliothèque dont nous dépendons a changé.

De plus, la setter fonctionne bien:

money.dollars += 2
print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 29 dollar and 12 cents.

money.cents += 10
print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 29 dollar and 22 cents.
18
Cleb

J'ai lu tous les articles ici et me suis rendu compte que nous aurions peut-être besoin d'un exemple concret, Pourquoi, en fait, nous avons @property? Alors, considérons une application Flask dans laquelle vous utilisez un système d'authentification. Vous déclarez un utilisateur modèle en models.py:

class User(UserMixin, db.Model):
    __table= 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, index=True)
    username = db.Column(db.String(64), unique=True, index=True)
    password_hash = db.Column(db.String(128))

    ...

    @property
    def password(self):
        raise AttributeError('password is not a readable attribute')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

Dans ce code, nous avons l'attribut "caché" password en utilisant @property qui déclenche une assertion AttributeError lorsque vous essayez d'y accéder directement, tandis que nous utilisions @ property.setter pour définir la variable d'instance réelle password_hash.

Maintenant, dans auth/views.py, nous pouvons instancier un utilisateur avec:

...
@auth.route('/register', methods=['GET', 'POST'])
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        user = User(email=form.email.data,
                    username=form.username.data,
                    password=form.password.data)
        db.session.add(user)
        db.session.commit()
...

Remarquez l'attribut password qui provient d'un formulaire d'inscription lorsqu'un utilisateur remplit le formulaire. La confirmation du mot de passe se produit au début avec EqualTo('password', message='Passwords must match') (au cas où vous vous le demanderiez, mais les formulaires Flask associés à un sujet différent).

J'espère que cet exemple sera utile 

12
Leo Skhrnkv

Commençons par les décorateurs Python.

Un décorateur Python est une fonction qui permet d’ajouter des fonctionnalités supplémentaires à une fonction déjà définie. 

En Python, tout est objet, En Python, tout est objet. Les fonctions en Python sont des objets de première classe, ce qui signifie qu’elles peuvent être référencées par une variable, ajoutées aux listes, passées en tant qu’arguments à une autre fonction, etc.

Considérez l'extrait de code suivant.

def decorator_func(fun):
    def wrapper_func():
        print("Wrapper function started")
        fun()
        print("Given function decorated")
        # Wrapper function add something to the passed function and decorator 
        # returns the wrapper function
    return wrapper_func

def say_bye():
    print("bye!!")

say_bye = decorator_func(say_bye)
say_bye()

# Output:
#  Wrapper function started
#  bye
#  Given function decorated

Ici, nous pouvons dire que la fonction décoratrice a modifié notre fonction say_hello et y a ajouté des lignes de code supplémentaires.

Syntaxe Python pour décorateur

def decorator_func(fun):
    def wrapper_func():
        print("Wrapper function started")
        fun()
        print("Given function decorated")
        # Wrapper function add something to the passed function and decorator 
        # returns the wrapper function
    return wrapper_func

@decorator_func
def say_bye():
    print("bye!!")

say_bye()

Terminons tout par rapport à un scénario, mais avant cela, parlons de quelques principes géniaux.

Les getters et les setters sont utilisés dans de nombreux langages de programmation orientés objet pour garantir le principe de l'encapsulation de données (est considéré comme le regroupement de données avec les méthodes qui fonctionnent sur ces données).

Ces méthodes sont bien sûr le getter pour récupérer les données et le configurateur pour changer les données. 

Selon ce principe, les attributs d'une classe sont privés pour les cacher et les protéger d'un autre code.

Yup, @property est fondamentalement une façon pythonique d'utiliser des accesseurs et des setters.

Python a un grand concept appelé propriété qui simplifie beaucoup la vie d'un programmeur orienté objet.

Supposons que vous décidiez de créer une classe pouvant stocker la température en degrés Celsius. 

class Celsius:
def __init__(self, temperature = 0):
    self.set_temperature(temperature)

def to_Fahrenheit(self):
    return (self.get_temperature() * 1.8) + 32

def get_temperature(self):
    return self._temperature

def set_temperature(self, value):
    if value < -273:
        raise ValueError("Temperature below -273 is not possible")
    self._temperature = value

Code refactorisé, voici comment nous aurions pu le réaliser avec la propriété.

En Python, propriété () est une fonction intégrée qui crée et retourne un objet de propriété.

Un objet de propriété a trois méthodes, getter (), setter () et delete ().

class Celsius:
def __init__(self, temperature = 0):
    self.temperature = temperature

def to_Fahrenheit(self):
    return (self.temperature * 1.8) + 32

def get_temperature(self):
    print("Getting value")
    return self.temperature

def set_temperature(self, value):
    if value < -273:
        raise ValueError("Temperature below -273 is not possible")
    print("Setting value")
    self.temperature = value

temperature = property(get_temperature,set_temperature)

Ici,

temperature = property(get_temperature,set_temperature)

aurait pu être décomposé comme,

# make empty property
temperature = property()
# assign fget
temperature = temperature.getter(get_temperature)
# assign fset
temperature = temperature.setter(set_temperature)

Point à noter:

  • get_temperature reste une propriété au lieu d'une méthode.

Vous pouvez maintenant accéder à la valeur de la température en écrivant.

C = Celsius()
C.temperature
# instead of writing C.get_temperature()

Nous pouvons continuer et ne pas définir les noms get_temperature _ et set_température car ils sont inutiles et polluer l'espace de noms de la classe.

La manière Pythonic de traiter le problème ci-dessus consiste à utiliser @property.

class Celsius:
    def __init__(self, temperature = 0):
        self.temperature = temperature

    def to_Fahrenheit(self):
        return (self.temperature * 1.8) + 32

    @property
    def temperature(self):
        print("Getting value")
        return self.temperature

    @temperature.setter
    def temperature(self, value):
        if value < -273:
            raise ValueError("Temperature below -273 is not possible")
        print("Setting value")
        self.temperature = value

Points à noter -

  1. Une méthode utilisée pour obtenir une valeur est décorée avec "@property".
  2. La méthode qui doit fonctionner en tant que setter est décorée avec "@ temperature.setter". Si la fonction avait été appelée "x", il faudrait la décorer avec "@ x.setter".
  3. Nous avons écrit "deux" méthodes avec le même nom et un nombre différent de paramètres "def temperature (self)" et "def temperature (self, x)".

Comme vous pouvez le constater, le code est nettement moins élégant.

Parlons maintenant d’un scénario pratique dans la vie réelle.

Disons que vous avez conçu une classe comme suit:

class OurClass:

    def __init__(self, a):
        self.x = a


y = OurClass(10)
print(y.x)

Supposons maintenant que notre classe est devenue populaire parmi les clients et qu'ils ont commencé à l'utiliser dans leurs programmes. Ils ont fait toutes sortes d'affectations à l'objet.

Et un jour fatidique, un client de confiance est venu nous voir et a suggéré que "x" devait être une valeur comprise entre 0 et 1000, c'est vraiment un scénario horrible!

En raison des propriétés, rien de plus simple: nous créons une version de propriété de "x".

class OurClass:

    def __init__(self,x):
        self.x = x

    @property
    def x(self):
        return self.__x

    @x.setter
    def x(self, x):
        if x < 0:
            self.__x = 0
        Elif x > 1000:
            self.__x = 1000
        else:
            self.__x = x

C’est génial, n’est-ce pas? Vous pouvez commencer par la mise en oeuvre la plus simple qui soit, et vous êtes libre de migrer ultérieurement vers une version de propriété sans avoir à changer d’interface! Les propriétés ne remplacent donc pas les accesseurs et les passeurs! 

Vous pouvez vérifier cette implémentation ici

5
Divyanshu Rawat

Ce point a été éclairci par de nombreuses personnes qui se trouvaient là-haut, mais voici un point direct sur lequel j’étais en train de chercher .

class UtilityMixin():
    @property
    def get_config(self):
        return "This is property"

L'appel de la fonction "get_config ()" fonctionnera comme ceci.

util = UtilityMixin()
print(util.get_config)

Si vous remarquez que je n’ai pas utilisé de crochets "()" pour appeler la fonction. C’est la chose fondamentale que je cherchais pour le décorateur @property. Pour que vous puissiez utiliser votre fonction comme une variable.

5
Devendra Bhat

property est une classe derrière @property décorateur.

Vous pouvez toujours vérifier ceci:

print(property) #<class 'property'>

J'ai réécrit l'exemple de help(property) pour montrer que la syntaxe @property

class C:
    def __init__(self):
        self._x=None

    @property 
    def x(self):
        return self._x

    @x.setter 
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

c = C()
c.x="a"
print(c.x)

est fonctionnellement identique à la syntaxe property():

class C:
    def __init__(self):
        self._x=None

    def g(self):
        return self._x

    def s(self, v):
        self._x = v

    def d(self):
        del self._x

    prop = property(g,s,d)

c = C()
c.x="a"
print(c.x)

Comme vous pouvez le constater, l'utilisation de la propriété est la même.

Pour répondre à la question, le décorateur @property est implémenté via la classe property.


La question est donc d’expliquer un peu la classe property. Cette ligne:

prop = property(g,s,d)

Était l'initialisation. Nous pouvons le réécrire comme ceci:

prop = property(fget=g,fset=s,fdel=d)

La signification de fget, fset et fdel:

 |    fget
 |      function to be used for getting an attribute value
 |    fset
 |      function to be used for setting an attribute value
 |    fdel
 |      function to be used for del'ing an attribute
 |    doc
 |      docstring

L'image suivante montre les triplets que nous avons, de la classe property:

 enter image description here 

__get__, __set__ et __delete__ peuvent être remplacés par substitués . C'est l'implémentation du motif de descripteur en Python.

En général, un descripteur est un attribut d'objet avec "comportement de liaison", un accès dont l'attribut a été remplacé par des méthodes du protocole de descripteur.

Nous pouvons également utiliser les méthodes property setter, getter et deleter pour lier la fonction à la propriété. Vérifiez l'exemple suivant. La méthode s2 de la classe C définira la propriété doubled .

class C:
    def __init__(self):
        self._x=None

    def g(self):
        return self._x

    def s(self, x):
        self._x = x

    def d(self):
        del self._x

    def s2(self,x):
        self._x=x+x


    x=property(g)
    x=x.setter(s)
    x=x.deleter(d)      


c = C()
c.x="a"
print(c.x) # outputs "a"

C.x=property(C.g, C.s2)
C.x=C.x.deleter(C.d)
c2 = C()
c2.x="a"
print(c2.x) # outputs "aa"
1
prosti

Une propriété peut être déclarée de deux manières.

  • Création des méthodes getter et setter pour un attribut, puis transmission de celles-ci en tant qu'argument à la fonction property
  • Utilisation du décorateur @property.

Vous pouvez consulter quelques exemples que j'ai écrits à propos de properties dans python

1
nvd

Voici un autre exemple:

##
## Python Properties Example
##
class GetterSetterExample( object ):
    ## Set the default value for x ( we reference it using self.x, set a value using self.x = value )
    __x = None


##
## On Class Initialization - do something... if we want..
##
def __init__( self ):
    ## Set a value to __x through the getter / setter... Since __x is defined above, this doesn't need to be set...
    self.x = 1234

    return None


##
## Define x as a property, ie a getter - All getters should have a default value arg, so I added it - it will not be passed in when setting a value, so you need to set the default here so it will be used..
##
@property
def x( self, _default = None ):
    ## I added an optional default value argument as all getters should have this - set it to the default value you want to return...
    _value = ( self.__x, _default )[ self.__x == None ]

    ## Debugging - so you can see the order the calls are made...
    print( '[ Test Class ] Get x = ' + str( _value ) )

    ## Return the value - we are a getter afterall...
    return _value


##
## Define the setter function for x...
##
@x.setter
def x( self, _value = None ):
    ## Debugging - so you can see the order the calls are made...
    print( '[ Test Class ] Set x = ' + str( _value ) )

    ## This is to show the setter function works.... If the value is above 0, set it to a negative value... otherwise keep it as is ( 0 is the only non-negative number, it can't be negative or positive anyway )
    if ( _value > 0 ):
        self.__x = -_value
    else:
        self.__x = _value


##
## Define the deleter function for x...
##
@x.deleter
def x( self ):
    ## Unload the assignment / data for x
    if ( self.__x != None ):
        del self.__x


##
## To String / Output Function for the class - this will show the property value for each property we add...
##
def __str__( self ):
    ## Output the x property data...
    print( '[ x ] ' + str( self.x ) )


    ## Return a new line - technically we should return a string so it can be printed where we want it, instead of printed early if _data = str( C( ) ) is used....
    return '\n'

##
##
##
_test = GetterSetterExample( )
print( _test )

## For some reason the deleter isn't being called...
del _test.x

Fondamentalement, le même que l’exemple C (objet), sauf que j’utilise plutôt x ... Je n’initialise pas non plus dans __init - ... eh bien, oui, mais il peut être supprimé car __x est défini comme faisant partie de la classe ....

La sortie est:

[ Test Class ] Set x = 1234
[ Test Class ] Get x = -1234
[ x ] -1234

et si je commente le self.x = 1234 dans init , alors le résultat est:

[ Test Class ] Get x = None
[ x ] None

et si je règle _default = None sur _default = 0 dans la fonction getter (tous les getters devraient avoir une valeur par défaut mais elle n'est pas transmise par les valeurs de propriété de ce que j'ai vu afin que vous puissiez la définir ici, et ce n'est pas grave car vous pouvez définir la valeur par défaut une fois et l'utiliser partout), à savoir: def x (self, _default = 0):

[ Test Class ] Get x = 0
[ x ] 0

Remarque: La logique de lecture est juste là pour que la valeur soit manipulée par elle afin de s'assurer qu'elle est manipulée par elle - la même chose pour les instructions d'impression ...

Remarque: je suis habitué à Lua et je suis capable de créer dynamiquement plus de 10 aides lorsque j'appelle une fonction unique et que j'ai créé quelque chose de similaire pour Python sans utiliser de propriétés et que cela fonctionne dans une certaine mesure, mais même si les fonctions ont été créées auparavant. étant utilisé, il y a toujours des problèmes avec le fait qu'ils soient appelés avant d'être créés, ce qui est étrange car ce n'est pas codé de cette façon ... Je préfère la flexibilité des méta-tables Lua et le fait que je peux utiliser de réels setters/getters Au lieu d’accéder directement à une variable, j’aime bien la rapidité avec laquelle certaines choses peuvent être construites avec Python, par exemple les programmes graphiques. Bien que celui que je conçois ne soit pas possible sans beaucoup de bibliothèques supplémentaires - si je le code dans AutoHotkey, je peux accéder directement aux appels dll dont j'ai besoin, et la même chose peut être faite en Java, C #, C++, etc. - peut-être que je Je n'ai pas encore trouvé le bon choix, mais je peux passer de Python à ce projet ..

Note: Le code dans ce forum est cassé - je devais ajouter des espaces dans la première partie du code pour que cela fonctionne - lors du copier/coller, assurez-vous de convertir tous les espaces en onglets .... J'utilise des onglets pour Python car dans un fichier de 10 000 lignes d'une taille pouvant aller de 512 Ko à 1 Mo avec des espaces et de 100 à 200 Ko avec des onglets, ce qui équivaut à une différence énorme en termes de taille de fichier et de réduction du temps de traitement ...

Les onglets peuvent également être ajustés par utilisateur. Ainsi, si vous préférez 2 espaces de largeur, 4, 8 ou tout ce que vous pouvez faire, cela signifie qu’il est judicieux pour les développeurs déficients visuels.

Remarque: Toutes les fonctions définies dans la classe ne sont pas correctement mises en retrait à cause d'un bogue dans le logiciel de forum. Assurez-vous de l'indenter si vous copiez/collez

1
Acecool

Une remarque: Pour moi, pour Python 2.x, @property n'a pas fonctionné comme annoncé quand je n'ai pas hérité de l'objet formulaire:

class A():
    pass

mais a travaillé quand:

class A(object):
    pass

pour Pyhton 3, a toujours travaillé

0