7371 Stimmen

Was sind Metaklassen in Python?

Was sind Metaklassen in Python und wofür werden sie verwendet?

164voto

Ich denke, die ONLamp-Einführung in die Metaklassenprogrammierung ist gut geschrieben und bietet eine wirklich gute Einführung in das Thema, obwohl sie schon einige Jahre alt ist.

http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html (archiviert unter https://web.archive.org/web/20080206005253/http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html )

Kurz gesagt: Eine Klasse ist ein Bauplan für die Erzeugung einer Instanz, eine Metaklasse ist ein Bauplan für die Erzeugung einer Klasse. Es ist leicht zu erkennen, dass in Python Klassen ebenfalls Objekte erster Klasse sein müssen, um dieses Verhalten zu ermöglichen.

Ich habe selbst nie eine geschrieben, aber ich denke, eine der schönsten Verwendungen von Metaklassen findet sich in der Django-Framework . Die Modellklassen verwenden einen Metaklassenansatz, um einen deklarativen Stil für das Schreiben neuer Modelle oder Formularklassen zu ermöglichen. Während die Metaklasse die Klasse erstellt, erhalten alle Mitglieder die Möglichkeit, die Klasse selbst anzupassen.

Was noch zu sagen bleibt, ist: Wenn Sie nicht wissen, was Metaklassen sind, ist die Wahrscheinlichkeit, dass Sie werden sie nicht benötigen beträgt 99 %.

151voto

Was sind Metaklassen? Wofür verwenden Sie sie?

TLDR: Eine Metaklasse instanziiert und definiert das Verhalten einer Klasse, genauso wie eine Klasse das Verhalten einer Instanz instanziiert und definiert.

Pseudocode:

>>> Class(...)
instance

Das oben Gesagte sollte Ihnen bekannt vorkommen. Nun, woher kommt Class herkommen? Es ist eine Instanz einer Metaklasse (auch Pseudocode):

>>> Metaclass(...)
Class

In echtem Code können wir die Standard-Metaklasse übergeben, type alles, was wir brauchen, um eine Klasse zu instanziieren, und wir erhalten eine Klasse:

>>> type('Foo', (object,), {}) # requires a name, bases, and a namespace
<class '__main__.Foo'>

Anders formuliert

  • Eine Klasse ist für eine Instanz das, was eine Metaklasse für eine Klasse ist.

    Wenn wir ein Objekt instanziieren, erhalten wir eine Instanz:

    >>> object()                          # instantiation of class
    <object object at 0x7f9069b4e0b0>     # instance

    Gleiches gilt, wenn wir eine Klasse explizit mit der Standard-Metaklasse definieren, type instanziieren wir es:

    >>> type('Object', (object,), {})     # instantiation of metaclass
    <class '__main__.Object'>             # instance
  • Anders ausgedrückt: Eine Klasse ist eine Instanz einer Metaklasse:

    >>> isinstance(object, type)
    True
  • Oder anders ausgedrückt: Eine Metaklasse ist die Klasse einer Klasse.

    >>> type(object) == type
    True
    >>> object.__class__
    <class 'type'>

Wenn Sie eine Klassendefinition schreiben und Python sie ausführt, verwendet es eine Metaklasse, um das Klassenobjekt zu instanziieren (das wiederum verwendet wird, um Instanzen dieser Klasse zu instanziieren).

Genauso wie wir Klassendefinitionen verwenden können, um das Verhalten von benutzerdefinierten Objektinstanzen zu ändern, können wir eine Metaklassendefinition verwenden, um das Verhalten eines Klassenobjekts zu ändern.

Wofür können sie verwendet werden? Von der docs :

Die Einsatzmöglichkeiten von Metaklassen sind grenzenlos. Einige Ideen, die untersucht wurden, umfassen Protokollierung, Schnittstellenprüfung, automatische Delegation, automatische Eigenschaftserstellung, Proxies, Frameworks und automatische Ressourcensperrung/Synchronisierung.

Dennoch wird den Benutzern in der Regel empfohlen, die Verwendung von Metaklassen zu vermeiden, sofern dies nicht unbedingt erforderlich ist.

Sie verwenden eine Metaklasse jedes Mal, wenn Sie eine Klasse erstellen:

Wenn Sie eine Klassendefinition schreiben, zum Beispiel wie diese,

class Foo(object): 
    'demo'

Sie instanziieren ein Klassenobjekt.

>>> Foo
<class '__main__.Foo'>
>>> isinstance(Foo, type), isinstance(Foo, object)
(True, True)

Es ist dasselbe wie der funktionale Aufruf von type mit den entsprechenden Argumenten und weist das Ergebnis einer Variablen mit diesem Namen zu:

name = 'Foo'
bases = (object,)
namespace = {'__doc__': 'demo'}
Foo = type(name, bases, namespace)

Beachten Sie, dass einige Dinge automatisch in die __dict__ d.h. der Namensraum:

>>> Foo.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, 
'__module__': '__main__', '__weakref__': <attribute '__weakref__' 
of 'Foo' objects>, '__doc__': 'demo'})

Le site Metaklasse des von uns erstellten Objekts ist in beiden Fällen type .

(Eine Randbemerkung zu den Inhalten der Klasse __dict__ : __module__ ist da, weil Klassen wissen müssen, wo sie definiert sind, und __dict__ y __weakref__ sind da, weil wir nicht definieren __slots__ - wenn wir definieren. __slots__ sparen wir ein wenig Platz in den Instanzen, da wir die Möglichkeit haben, die __dict__ y __weakref__ indem man sie ausschließt. Zum Beispiel:

>>> Baz = type('Bar', (object,), {'__doc__': 'demo', '__slots__': ()})
>>> Baz.__dict__
mappingproxy({'__doc__': 'demo', '__slots__': (), '__module__': '__main__'})

... aber ich schweife ab.)

Wir können erweitern type genau wie jede andere Klassendefinition:

Hier ist die Standardeinstellung __repr__ von Klassen:

>>> Foo
<class '__main__.Foo'>

Eines der wertvollsten Dinge, die wir beim Schreiben eines Python-Objekts standardmäßig tun können, ist, es mit einer guten __repr__ . Wenn wir anrufen help(repr) erfahren wir, dass es einen guten Test für eine __repr__ die auch einen Test auf Gleichheit erfordert - obj == eval(repr(obj)) . Die folgende einfache Implementierung von __repr__ y __eq__ für Klasseninstanzen unserer Typklasse bietet uns eine Demonstration, die den Standard verbessern kann __repr__ von Klassen:

class Type(type):
    def __repr__(cls):
        """
        >>> Baz
        Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
        >>> eval(repr(Baz))
        Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
        """
        metaname = type(cls).__name__
        name = cls.__name__
        parents = ', '.join(b.__name__ for b in cls.__bases__)
        if parents:
            parents += ','
        namespace = ', '.join(': '.join(
          (repr(k), repr(v) if not isinstance(v, type) else v.__name__))
               for k, v in cls.__dict__.items())
        return '{0}(\'{1}\', ({2}), {{{3}}})'.format(metaname, name, parents, namespace)
    def __eq__(cls, other):
        """
        >>> Baz == eval(repr(Baz))
        True            
        """
        return (cls.__name__, cls.__bases__, cls.__dict__) == (
                other.__name__, other.__bases__, other.__dict__)

Wenn wir nun ein Objekt mit dieser Metaklasse erstellen, wird die __repr__ in der Befehlszeile bietet einen viel weniger hässlichen Anblick als die Standardeinstellung:

>>> class Bar(object): pass
>>> Baz = Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
>>> Baz
Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})

Mit einem schönen __repr__ für die Klasseninstanz definiert ist, haben wir eine bessere Möglichkeit, unseren Code zu debuggen. Allerdings ist eine weitergehende Überprüfung mit eval(repr(Class)) ist unwahrscheinlich (da es ziemlich unmöglich wäre, Funktionen von ihrem Standardwert zu evalieren __repr__ 's).

Eine erwartete Verwendung: __prepare__ einen Namensraum

Wenn wir zum Beispiel wissen wollen, in welcher Reihenfolge die Methoden einer Klasse erstellt werden, können wir ein geordnetes Diktat als Namensraum der Klasse angeben. Wir würden dies tun mit __prepare__ die gibt das Namespace-Dict für die Klasse zurück, wenn sie in Python 3 implementiert ist :

from collections import OrderedDict

class OrderedType(Type):
    @classmethod
    def __prepare__(metacls, name, bases, **kwargs):
        return OrderedDict()
    def __new__(cls, name, bases, namespace, **kwargs):
        result = Type.__new__(cls, name, bases, dict(namespace))
        result.members = tuple(namespace)
        return result

Und Verwendung:

class OrderedMethodsObject(object, metaclass=OrderedType):
    def method1(self): pass
    def method2(self): pass
    def method3(self): pass
    def method4(self): pass

Und jetzt haben wir eine Aufzeichnung der Reihenfolge, in der diese Methoden (und andere Klassenattribute) erstellt wurden:

>>> OrderedMethodsObject.members
('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4')

Anmerkung: Dieses Beispiel wurde aus dem Dokumentation - die neue enum in der Standardbibliothek tut dies.

Wir haben also eine Metaklasse instanziiert, indem wir eine Klasse erstellt haben. Wir können die Metaklasse auch wie jede andere Klasse behandeln. Sie hat eine Reihenfolge der Methodenauflösung:

>>> inspect.getmro(OrderedType)
(<class '__main__.OrderedType'>, <class '__main__.Type'>, <class 'type'>, <class 'object'>)

Und es hat ungefähr die richtige repr (die wir nicht mehr auswerten können, es sei denn, wir finden einen Weg, unsere Funktionen darzustellen.):

>>> OrderedMethodsObject
OrderedType('OrderedMethodsObject', (object,), {'method1': <function OrderedMethodsObject.method1 at 0x0000000002DB01E0>, 'members': ('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4'), 'method3': <function OrderedMet
hodsObject.method3 at 0x0000000002DB02F0>, 'method2': <function OrderedMethodsObject.method2 at 0x0000000002DB0268>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'OrderedMethodsObject' objects>, '__doc__': None, '__d
ict__': <attribute '__dict__' of 'OrderedMethodsObject' objects>, 'method4': <function OrderedMethodsObject.method4 at 0x0000000002DB0378>})

112voto

Ethan Furman Punkte 57238

Python 3 Aktualisierung

Es gibt (an dieser Stelle) zwei wichtige Methoden in einer Metaklasse:

  • __prepare__ und
  • __new__

__prepare__ können Sie eine benutzerdefinierte Zuordnung (z. B. eine OrderedDict ), der als Namespace verwendet wird, während die Klasse erstellt wird. Sie müssen eine Instanz des von Ihnen gewählten Namespace zurückgeben. Wenn Sie nicht implementieren __prepare__ eine normale dict verwendet wird.

__new__ ist für die eigentliche Erstellung/Änderung der endgültigen Klasse verantwortlich.

Eine einfache Metaklasse, die nichts Besonderes ist, wäre das:

class Meta(type):

    def __prepare__(metaclass, cls, bases):
        return dict()

    def __new__(metacls, cls, bases, clsdict):
        return super().__new__(metacls, cls, bases, clsdict)

Ein einfaches Beispiel:

Angenommen, Sie möchten, dass ein einfacher Validierungscode für Ihre Attribute ausgeführt wird - z. B. muss es sich immer um ein int oder eine str . Ohne eine Metaklasse würde Ihre Klasse etwa so aussehen:

class Person:
    weight = ValidateType('weight', int)
    age = ValidateType('age', int)
    name = ValidateType('name', str)

Wie Sie sehen können, müssen Sie den Namen des Attributs zweimal wiederholen. Dies führt zu Tippfehlern und ärgerlichen Fehlern.

Eine einfache Metaklasse kann dieses Problem lösen:

class Person(metaclass=Validator):
    weight = ValidateType(int)
    age = ValidateType(int)
    name = ValidateType(str)

So würde die Metaklasse aussehen (ohne Verwendung von __prepare__ da sie nicht benötigt wird):

class Validator(type):
    def __new__(metacls, cls, bases, clsdict):
        # search clsdict looking for ValidateType descriptors
        for name, attr in clsdict.items():
            if isinstance(attr, ValidateType):
                attr.name = name
                attr.attr = '_' + name
        # create final class and return it
        return super().__new__(metacls, cls, bases, clsdict)

Ein Musterlauf von:

p = Person()
p.weight = 9
print(p.weight)
p.weight = '9'

produziert:

9
Traceback (most recent call last):
  File "simple_meta.py", line 36, in <module>
    p.weight = '9'
  File "simple_meta.py", line 24, in __set__
    (self.name, self.type, value))
TypeError: weight must be of type(s) <class 'int'> (got '9')

Note : Dieses Beispiel ist einfach genug, dass es auch mit einem Klassendekorator hätte erreicht werden können, aber vermutlich würde eine echte Metaklasse viel mehr tun.

Die 'ValidateType'-Klasse als Referenz:

class ValidateType:
    def __init__(self, type):
        self.name = None  # will be set by metaclass
        self.attr = None  # will be set by metaclass
        self.type = type
    def __get__(self, inst, cls):
        if inst is None:
            return self
        else:
            return inst.__dict__[self.attr]
    def __set__(self, inst, value):
        if not isinstance(value, self.type):
            raise TypeError('%s must be of type(s) %s (got %r)' %
                    (self.name, self.type, value))
        else:
            inst.__dict__[self.attr] = value

2 Stimmen

Beachten Sie, dass Sie seit Python 3.6 die Option __set_name__(cls, name) im Deskriptor ( ValidateType ), um den Namen im Deskriptor zu setzen ( self.name und in diesem Fall auch self.attr ). Dies wurde hinzugefügt, um nicht in Metaklassen für diesen speziellen, allgemeinen Anwendungsfall eintauchen zu müssen (siehe PEP 487).

103voto

Michael Ekoka Punkte 17537

Die Rolle einer Metaklasse __call__() Methode bei der Erstellung einer Klasseninstanz

Wenn Sie sich länger als ein paar Monate mit Python-Programmierung beschäftigt haben, werden Sie irgendwann über Code stolpern, der so aussieht:

# define a class
class SomeClass(object):
    # ...
    # some definition here ...
    # ...

# create an instance of it
instance = SomeClass()

# then call the object as if it's a function
result = instance('foo', 'bar')

Letzteres ist möglich, wenn Sie die Funktion __call__() magische Methode auf die Klasse.

class SomeClass(object):
    # ...
    # some definition here ...
    # ...

    def __call__(self, foo, bar):
        return bar + foo

Le site __call__() Methode wird aufgerufen, wenn eine Instanz einer Klasse als Callable verwendet wird. Aber wie wir in den vorherigen Antworten gesehen haben, ist eine Klasse selbst eine Instanz einer Metaklasse, so dass wir, wenn wir die Klasse als Callable verwenden (d.h. wenn wir eine Instanz von ihr erzeugen), eigentlich die Metaklasse aufrufen. __call__() Methode. An dieser Stelle sind die meisten Python-Programmierer ein wenig verwirrt, weil ihnen gesagt wurde, dass bei der Erstellung einer Instanz wie dieser instance = SomeClass() du rufst seine __init__() Methode. Einige, die ein wenig tiefer gegraben haben, wissen, dass vor __init__() Es gibt __new__() . Nun, heute wird eine weitere Schicht der Wahrheit enthüllt, bevor __new__() da ist die Metaklasse' __call__() .

Betrachten wir die Methodenaufrufkette speziell aus der Perspektive der Erstellung einer Instanz einer Klasse.

Dies ist eine Metaklasse, die genau den Moment protokolliert, bevor eine Instanz erzeugt wird, und den Moment, in dem sie sie zurückgibt.

class Meta_1(type):
    def __call__(cls):
        print "Meta_1.__call__() before creating an instance of ", cls
        instance = super(Meta_1, cls).__call__()
        print "Meta_1.__call__() about to return instance."
        return instance

Dies ist eine Klasse, die diese Metaklasse verwendet

class Class_1(object):

    __metaclass__ = Meta_1

    def __new__(cls):
        print "Class_1.__new__() before creating an instance."
        instance = super(Class_1, cls).__new__(cls)
        print "Class_1.__new__() about to return instance."
        return instance

    def __init__(self):
        print "entering Class_1.__init__() for instance initialization."
        super(Class_1,self).__init__()
        print "exiting Class_1.__init__()."

Und nun erstellen wir eine Instanz von Class_1

instance = Class_1()
# Meta_1.__call__() before creating an instance of <class '__main__.Class_1'>.
# Class_1.__new__() before creating an instance.
# Class_1.__new__() about to return instance.
# entering Class_1.__init__() for instance initialization.
# exiting Class_1.__init__().
# Meta_1.__call__() about to return instance.

Beachten Sie, dass der obige Code eigentlich nichts weiter tut, als die Aufgaben zu protokollieren. Jede Methode delegiert die eigentliche Arbeit an die Implementierung der übergeordneten Methode, wodurch das Standardverhalten beibehalten wird. Da type es Meta_1 der übergeordneten Klasse ( type die Standard-Eltern-Metaklasse) und unter Berücksichtigung der Reihenfolge der obigen Ausgabe haben wir nun einen Anhaltspunkt dafür, wie die Pseudo-Implementierung von type.__call__() :

class type:
    def __call__(cls, *args, **kwarg):

        # ... maybe a few things done to cls here

        # then we call __new__() on the class to create an instance
        instance = cls.__new__(cls, *args, **kwargs)

        # ... maybe a few things done to the instance here

        # then we initialize the instance with its __init__() method
        instance.__init__(*args, **kwargs)

        # ... maybe a few more things done to instance here

        # then we return it
        return instance

Wir können sehen, dass die Metaklasse' __call__() Methode ist diejenige, die zuerst aufgerufen wird. Sie delegiert dann die Erzeugung der Instanz an die Methode der Klasse __new__() Methode und die Initialisierung der Instanz __init__() . Sie ist auch diejenige, die letztendlich die Instanz zurückgibt.

Aus den obigen Ausführungen ergibt sich, dass die Metaklasse' __call__() wird auch die Möglichkeit gegeben, zu entscheiden, ob ein Anruf bei Class_1.__new__() o Class_1.__init__() wird schließlich gemacht werden. Im Laufe seiner Ausführung könnte es tatsächlich ein Objekt zurückgeben, das von keiner der beiden Methoden berührt wurde. Nehmen Sie zum Beispiel diesen Ansatz für das Singleton-Muster:

class Meta_2(type):
    singletons = {}

    def __call__(cls, *args, **kwargs):
        if cls in Meta_2.singletons:
            # we return the only instance and skip a call to __new__()
            # and __init__()
            print ("{} singleton returning from Meta_2.__call__(), "
                   "skipping creation of new instance.".format(cls))
            return Meta_2.singletons[cls]

        # else if the singleton isn't present we proceed as usual
        print "Meta_2.__call__() before creating an instance."
        instance = super(Meta_2, cls).__call__(*args, **kwargs)
        Meta_2.singletons[cls] = instance
        print "Meta_2.__call__() returning new instance."
        return instance

class Class_2(object):

    __metaclass__ = Meta_2

    def __new__(cls, *args, **kwargs):
        print "Class_2.__new__() before creating instance."
        instance = super(Class_2, cls).__new__(cls)
        print "Class_2.__new__() returning instance."
        return instance

    def __init__(self, *args, **kwargs):
        print "entering Class_2.__init__() for initialization."
        super(Class_2, self).__init__()
        print "exiting Class_2.__init__()."

Sehen wir uns an, was passiert, wenn wir wiederholt versuchen, ein Objekt des Typs Class_2

a = Class_2()
# Meta_2.__call__() before creating an instance.
# Class_2.__new__() before creating instance.
# Class_2.__new__() returning instance.
# entering Class_2.__init__() for initialization.
# exiting Class_2.__init__().
# Meta_2.__call__() returning new instance.

b = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.

c = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.

a is b is c # True

3 Stimmen

Dies ist eine gute Ergänzung zu der zuvor hochgestimmten "akzeptierten Antwort". Sie bietet Beispiele für fortgeschrittene Programmierer zum Nachschlagen.

78voto

Craig Punkte 4028

A metaclass ist eine Klasse, die angibt, wie (eine) andere Klasse erstellt werden soll.

Dies ist ein Fall, bei dem ich sah metaclass als eine Lösung für mein Problem: Ich hatte ein wirklich kompliziertes Problem, das wahrscheinlich auch anders hätte gelöst werden können, aber ich habe mich dafür entschieden, es mit Hilfe einer metaclass . Aufgrund der Komplexität ist es eines der wenigen Module, die ich geschrieben habe, bei dem die Kommentare im Modul die Menge des geschriebenen Codes übertreffen. Hier ist es...

#!/usr/bin/env python

# Copyright (C) 2013-2014 Craig Phillips.  All rights reserved.

# This requires some explaining.  The point of this metaclass excercise is to
# create a static abstract class that is in one way or another, dormant until
# queried.  I experimented with creating a singlton on import, but that did
# not quite behave how I wanted it to.  See now here, we are creating a class
# called GsyncOptions, that on import, will do nothing except state that its
# class creator is GsyncOptionsType.  This means, docopt doesn't parse any
# of the help document, nor does it start processing command line options.
# So importing this module becomes really efficient.  The complicated bit
# comes from requiring the GsyncOptions class to be static.  By that, I mean
# any property on it, may or may not exist, since they are not statically
# defined; so I can't simply just define the class with a whole bunch of
# properties that are @property @staticmethods.
#
# So here's how it works:
#
# Executing 'from libgsync.options import GsyncOptions' does nothing more
# than load up this module, define the Type and the Class and import them
# into the callers namespace.  Simple.
#
# Invoking 'GsyncOptions.debug' for the first time, or any other property
# causes the __metaclass__ __getattr__ method to be called, since the class
# is not instantiated as a class instance yet.  The __getattr__ method on
# the type then initialises the class (GsyncOptions) via the __initialiseClass
# method.  This is the first and only time the class will actually have its
# dictionary statically populated.  The docopt module is invoked to parse the
# usage document and generate command line options from it.  These are then
# paired with their defaults and what's in sys.argv.  After all that, we
# setup some dynamic properties that could not be defined by their name in
# the usage, before everything is then transplanted onto the actual class
# object (or static class GsyncOptions).
#
# Another piece of magic, is to allow command line options to be set in
# in their native form and be translated into argparse style properties.
#
# Finally, the GsyncListOptions class is actually where the options are
# stored.  This only acts as a mechanism for storing options as lists, to
# allow aggregation of duplicate options or options that can be specified
# multiple times.  The __getattr__ call hides this by default, returning the
# last item in a property's list.  However, if the entire list is required,
# calling the 'list()' method on the GsyncOptions class, returns a reference
# to the GsyncListOptions class, which contains all of the same properties
# but as lists and without the duplication of having them as both lists and
# static singlton values.
#
# So this actually means that GsyncOptions is actually a static proxy class...
#
# ...And all this is neatly hidden within a closure for safe keeping.
def GetGsyncOptionsType():
    class GsyncListOptions(object):
        __initialised = False

    class GsyncOptionsType(type):
        def __initialiseClass(cls):
            if GsyncListOptions._GsyncListOptions__initialised: return

            from docopt import docopt
            from libgsync.options import doc
            from libgsync import __version__

            options = docopt(
                doc.__doc__ % __version__,
                version = __version__,
                options_first = True
            )

            paths = options.pop('<path>', None)
            setattr(cls, "destination_path", paths.pop() if paths else None)
            setattr(cls, "source_paths", paths)
            setattr(cls, "options", options)

            for k, v in options.iteritems():
                setattr(cls, k, v)

            GsyncListOptions._GsyncListOptions__initialised = True

        def list(cls):
            return GsyncListOptions

        def __getattr__(cls, name):
            cls.__initialiseClass()
            return getattr(GsyncListOptions, name)[-1]

        def __setattr__(cls, name, value):
            # Substitut option names: --an-option-name for an_option_name
            import re
            name = re.sub(r'^__', "", re.sub(r'-', "_", name))
            listvalue = []

            # Ensure value is converted to a list type for GsyncListOptions
            if isinstance(value, list):
                if value:
                    listvalue = [] + value
                else:
                    listvalue = [ None ]
            else:
                listvalue = [ value ]

            type.__setattr__(GsyncListOptions, name, listvalue)

    # Cleanup this module to prevent tinkering.
    import sys
    module = sys.modules[__name__]
    del module.__dict__['GetGsyncOptionsType']

    return GsyncOptionsType

# Our singlton abstract proxy class.
class GsyncOptions(object):
    __metaclass__ = GetGsyncOptionsType()

3 Stimmen

Pylint sagt, dass Ihr Code mit -1,03/10 bewertet wurde.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X