Wiele z dostarczonych odpowiedzi wymaga tak wielu wierszy na właściwość, tj. / I / lub - co uważam za brzydką lub żmudną implementację ze względu na powtarzalność wymaganą dla wielu właściwości itp. Wolę utrzymywać gotowanie na niskim poziomie / uprościć je, dopóki nie nie można go już uprościć, dopóki nie przyniesie to zbytniego celu.
W skrócie: w ukończonych pracach, jeśli powtórzę 2 wiersze kodu, zazwyczaj przekształcam go w funkcję pomocniczą z jednym wierszem itd. ... Upraszczam matematykę lub nieparzyste argumenty, takie jak (start_x, start_y, end_x, end_y) do (x, y, w, h) tj. x, y, x + w, y + h (czasami wymagające min / max lub jeśli w / h są ujemne i implementacja tego nie lubi, odejmę od x / y i abs w / h. itp.).
Zastąpienie wewnętrznych modułów pobierających / ustawiających jest dobrym rozwiązaniem, ale problem polega na tym, że musisz to zrobić dla każdej klasy lub nadać klasę tej bazie ... To nie działa dla mnie tak, jak wolałbym być swobodnie wybierać dzieci / rodziców do dziedziczenia, węzłów dziecięcych itp.
Stworzyłem rozwiązanie, które odpowiada na pytanie bez użycia typu danych Dict do dostarczania danych, ponieważ uważam, że wprowadzanie danych jest uciążliwe itp.
Moje rozwiązanie wymaga dodania 2 dodatkowych linii nad klasą, aby utworzyć klasę podstawową dla klasy, do której chcesz dodać właściwości, a następnie 1 linii na i masz możliwość dodania wywołań zwrotnych w celu kontrolowania danych, informowania o zmianach danych , ogranicz dane, które można ustawić na podstawie wartości i / lub typu danych, i wiele więcej.
Masz również opcję użycia _object.x, _object.x = wartość, _object.GetX (), _object.SetX (wartość) i są one obsługiwane w równoważny sposób.
Dodatkowo wartości są jedynymi danymi niestatycznymi, które są przypisane do instancji klasy, ale faktyczna właściwość jest przypisana do klasy, co oznacza rzeczy, których nie chcesz powtarzać, nie trzeba powtarzać ... może przypisać wartość domyślną, aby moduł pobierający nie potrzebował jej za każdym razem, chociaż istnieje opcja zastąpienia domyślnej wartości domyślnej, a istnieje inna opcja, więc moduł pobierający zwraca nieprzetworzoną przechowywaną wartość poprzez przesłanianie wartości domyślnych (uwaga: ta metoda oznacza, że surowa wartość jest przypisywana tylko wtedy, gdy przypisana jest wartość, w przeciwnym razie jest to Brak - gdy wartość to Resetuj, wówczas przypisuje Brak, itp.)
Istnieje również wiele funkcji pomocniczych - pierwsza właściwość, która zostanie dodana, dodaje do klasy około 2 pomocników do odwoływania się do wartości instancji ... Są to ResetAccessors (_key, ..) powtarzane varargs (wszystkie mogą być powtarzane przy użyciu nazwanych args ) i SetAccessors (_key, _value) z opcją dodawania więcej do klasy głównej w celu zwiększenia wydajności - planowane są: sposób na grupowanie akcesoriów, więc jeśli masz tendencję do resetowania kilku na raz, za każdym razem , możesz przypisać je do grupy i zresetować grupę zamiast powtarzania nazwanych kluczy za każdym razem i więcej.
Instancja / nieprzetworzona wartość przechowywana jest przechowywana w klasie. , klasa. odwołuje się do klasy Accessor, która przechowuje statyczne zmienne / wartości / funkcje dla właściwości. _klasa. jest samą właściwością, która jest wywoływana przy dostępie przez klasę instancji podczas ustawiania / pobierania itp.
Accessor _class .__ wskazuje na klasę, ale ponieważ jest ona wewnętrzna, należy ją przypisać do klasy, dlatego zdecydowałem się użyć __Name = AccessorFunc (...) do przypisania jej, pojedynczej linii na właściwość z wieloma opcjonalnymi argumenty do użycia (przy użyciu kluczowanych varargs, ponieważ są łatwiejsze i bardziej wydajne do identyfikacji i utrzymania) ...
Tworzę również wiele funkcji, jak wspomniano, niektóre z nich używają informacji o funkcji akcesorium, więc nie trzeba ich wywoływać (ponieważ w tej chwili jest to trochę niewygodne - w tej chwili musisz użyć _class. .FunctionName (_class_instance , args) - Poruszałem się przy użyciu stosu / śledzenia, aby pobrać odwołanie do instancji, aby pobrać wartość, dodając funkcje, które albo uruchamiają ten bit maratonu, albo dodając akcesory do obiektu i używając self (nazwał to, aby zaznaczyć, że dotyczy instancji i aby zachować dostęp do siebie, odwołania do klasy AccessorFunc i innych informacji z definicji funkcji).
Nie jest to do końca zrobione, ale jest fantastyczną stopą. Uwaga: Jeśli nie użyjesz __Name = AccessorFunc (...) do utworzenia właściwości, nie będziesz miał dostępu do klucza __, nawet jeśli zdefiniuję go w funkcji init. Jeśli to zrobisz, nie będzie żadnych problemów.
Pamiętaj też, że nazwa i klucz są różne ... Nazwa jest „formalna”, używana w funkcji tworzenia nazw funkcji, a klucz służy do przechowywania danych i dostępu do nich. tj. _class.x, gdzie mała litera x jest kluczem, nazwa będzie wielką literą X, więc GetX () jest funkcją zamiast Getx (), która wygląda trochę dziwnie. pozwala to self.x działać i wyglądać odpowiednio, ale także pozwalać GetX () i wyglądać odpowiednio.
Mam przykładową klasę skonfigurowaną z identycznym kluczem / nazwą i inną do pokazania. wiele funkcji pomocniczych utworzonych w celu wyprowadzenia danych (uwaga: nie wszystko jest kompletne), dzięki czemu można zobaczyć, co się dzieje.
Aktualna lista funkcji wykorzystujących klawisz: x, nazwa: X wyświetla jako:
Nie jest to bynajmniej wyczerpująca lista - jest kilka, które nie dotarły do tego w momencie publikowania ...
_instance.SetAccessors( _key, _value [ , _key, _value ] .. ) Instance Class Helper Function: Allows assigning many keys / values on a single line - useful for initial setup, or to minimize lines. In short: Calls this.Set<Name>( _value ) for each _key / _value pairing.
_instance.ResetAccessors( _key [ , _key ] .. ) Instance Class Helper Function: Allows resetting many key stored values to None on a single line. In short: Calls this.Reset<Name>() for each name provided.
Note: Functions below may list self.Get / Set / Name( _args ) - self is meant as the class instance reference in the cases below - coded as this in AccessorFuncBase Class.
this.GetX( _default_override = None, _ignore_defaults = False ) GET: Returns IF ISSET: STORED_VALUE .. IF IGNORE_DEFAULTS: None .. IF PROVIDED: DEFAULT_OVERRIDE ELSE: DEFAULT_VALUE 100
this.GetXRaw( ) RAW: Returns STORED_VALUE 100
this.IsXSet( ) ISSET: Returns ( STORED_VALUE != None ) True
this.GetXToString( ) GETSTR: Returns str( GET ) 100
this.GetXLen( _default_override = None, _ignore_defaults = False ) LEN: Returns len( GET ) 3
this.GetXLenToString( _default_override = None, _ignore_defaults = False ) LENSTR: Returns str( len( GET ) ) 3
this.GetXDefaultValue( ) DEFAULT: Returns DEFAULT_VALUE 1111
this.GetXAccessor( ) ACCESSOR: Returns ACCESSOR_REF ( self.__<key> ) [ AccessorFuncBase ] Key: x : Class ID: 2231452344344 : self ID: 2231448283848 Default: 1111 Allowed Types: {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"} Allowed Values: None
this.GetXAllowedTypes( ) ALLOWED_TYPES: Returns Allowed Data-Types {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"}
this.GetXAllowedValues( ) ALLOWED_VALUES: Returns Allowed Values None
this.GetXHelpers( ) HELPERS: Returns Helper Functions String List - ie what you're reading now... THESE ROWS OF TEXT
this.GetXKeyOutput( ) Returns information about this Name / Key ROWS OF TEXT
this.GetXGetterOutput( ) Returns information about this Name / Key ROWS OF TEXT
this.SetX( _value ) SET: STORED_VALUE Setter - ie Redirect to __<Key>.Set N / A
this.ResetX( ) RESET: Resets STORED_VALUE to None N / A
this.HasXGetterPrefix( ) Returns Whether or Not this key has a Getter Prefix... True
this.GetXGetterPrefix( ) Returns Getter Prefix... Get
this.GetXName( ) Returns Accessor Name - Typically Formal / Title-Case X
this.GetXKey( ) Returns Accessor Property Key - Typically Lower-Case x
this.GetXAccessorKey( ) Returns Accessor Key - This is to access internal functions, and static data... __x
this.GetXDataKey( ) Returns Accessor Data-Storage Key - This is the location where the class instance value is stored.. _x
Niektóre dane wyjściowe to:
To jest dla zupełnie nowej klasy utworzonej przy użyciu klasy Demo bez przypisanych danych innych niż nazwa (aby można ją było wydrukować), czyli _foo, nazwa zmiennej, której użyłem ...
_foo --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016
Key Getter Value | Raw Key Raw / Stored Value | Get Default Value Default Value | Get Allowed Types Allowed Types | Get Allowed Values Allowed Values |
Name: _foo | _Name: _foo | __Name.DefaultValue( ): AccessorFuncDemoClass | __Name.GetAllowedTypes( ) <class 'str'> | __Name.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
x: 1111 | _x: None | __x.DefaultValue( ): 1111 | __x.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __x.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
y: 2222 | _y: None | __y.DefaultValue( ): 2222 | __y.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __y.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
z: 3333 | _z: None | __z.DefaultValue( ): 3333 | __z.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __z.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Blah: <class 'int'> | _Blah: None | __Blah.DefaultValue( ): <class 'int'> | __Blah.GetAllowedTypes( ) <class 'str'> | __Blah.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Width: 1 | _Width: None | __Width.DefaultValue( ): 1 | __Width.GetAllowedTypes( ) (<class 'int'>, <class 'bool'>) | __Width.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Height: 0 | _Height: None | __Height.DefaultValue( ): 0 | __Height.GetAllowedTypes( ) <class 'int'> | __Height.GetAllowedValues( ) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
Depth: 2 | _Depth: None | __Depth.DefaultValue( ): 2 | __Depth.GetAllowedTypes( ) Saved Value Restricted to Authorized Values ONLY | __Depth.GetAllowedValues( ) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
this.IsNameSet( ): True this.GetName( ): _foo this.GetNameRaw( ): _foo this.GetNameDefaultValue( ): AccessorFuncDemoClass this.GetNameLen( ): 4 this.HasNameGetterPrefix( ): <class 'str'> this.GetNameGetterPrefix( ): None
this.IsXSet( ): False this.GetX( ): 1111 this.GetXRaw( ): None this.GetXDefaultValue( ): 1111 this.GetXLen( ): 4 this.HasXGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetXGetterPrefix( ): None
this.IsYSet( ): False this.GetY( ): 2222 this.GetYRaw( ): None this.GetYDefaultValue( ): 2222 this.GetYLen( ): 4 this.HasYGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetYGetterPrefix( ): None
this.IsZSet( ): False this.GetZ( ): 3333 this.GetZRaw( ): None this.GetZDefaultValue( ): 3333 this.GetZLen( ): 4 this.HasZGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetZGetterPrefix( ): None
this.IsBlahSet( ): False this.GetBlah( ): <class 'int'> this.GetBlahRaw( ): None this.GetBlahDefaultValue( ): <class 'int'> this.GetBlahLen( ): 13 this.HasBlahGetterPrefix( ): <class 'str'> this.GetBlahGetterPrefix( ): None
this.IsWidthSet( ): False this.GetWidth( ): 1 this.GetWidthRaw( ): None this.GetWidthDefaultValue( ): 1 this.GetWidthLen( ): 1 this.HasWidthGetterPrefix( ): (<class 'int'>, <class 'bool'>) this.GetWidthGetterPrefix( ): None
this.IsDepthSet( ): False this.GetDepth( ): 2 this.GetDepthRaw( ): None this.GetDepthDefaultValue( ): 2 this.GetDepthLen( ): 1 this.HasDepthGetterPrefix( ): None this.GetDepthGetterPrefix( ): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ): False this.GetHeight( ): 0 this.GetHeightRaw( ): None this.GetHeightDefaultValue( ): 0 this.GetHeightLen( ): 1 this.HasHeightGetterPrefix( ): <class 'int'> this.GetHeightGetterPrefix( ): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
I to po przypisaniu wszystkich właściwości _foo (oprócz nazwy) następujących wartości w tej samej kolejności: „ciąg”, 1,0, prawda, 9, 10, fałsz
this.IsNameSet( ): True this.GetName( ): _foo this.GetNameRaw( ): _foo this.GetNameDefaultValue( ): AccessorFuncDemoClass this.GetNameLen( ): 4 this.HasNameGetterPrefix( ): <class 'str'> this.GetNameGetterPrefix( ): None
this.IsXSet( ): True this.GetX( ): 10 this.GetXRaw( ): 10 this.GetXDefaultValue( ): 1111 this.GetXLen( ): 2 this.HasXGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetXGetterPrefix( ): None
this.IsYSet( ): True this.GetY( ): 10 this.GetYRaw( ): 10 this.GetYDefaultValue( ): 2222 this.GetYLen( ): 2 this.HasYGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetYGetterPrefix( ): None
this.IsZSet( ): True this.GetZ( ): 10 this.GetZRaw( ): 10 this.GetZDefaultValue( ): 3333 this.GetZLen( ): 2 this.HasZGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetZGetterPrefix( ): None
this.IsBlahSet( ): True this.GetBlah( ): string Blah this.GetBlahRaw( ): string Blah this.GetBlahDefaultValue( ): <class 'int'> this.GetBlahLen( ): 11 this.HasBlahGetterPrefix( ): <class 'str'> this.GetBlahGetterPrefix( ): None
this.IsWidthSet( ): True this.GetWidth( ): False this.GetWidthRaw( ): False this.GetWidthDefaultValue( ): 1 this.GetWidthLen( ): 5 this.HasWidthGetterPrefix( ): (<class 'int'>, <class 'bool'>) this.GetWidthGetterPrefix( ): None
this.IsDepthSet( ): True this.GetDepth( ): 9 this.GetDepthRaw( ): 9 this.GetDepthDefaultValue( ): 2 this.GetDepthLen( ): 1 this.HasDepthGetterPrefix( ): None this.GetDepthGetterPrefix( ): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ): True this.GetHeight( ): 9 this.GetHeightRaw( ): 9 this.GetHeightDefaultValue( ): 0 this.GetHeightLen( ): 1 this.HasHeightGetterPrefix( ): <class 'int'> this.GetHeightGetterPrefix( ): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
_foo --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016
Key Getter Value | Raw Key Raw / Stored Value | Get Default Value Default Value | Get Allowed Types Allowed Types | Get Allowed Values Allowed Values |
Name: _foo | _Name: _foo | __Name.DefaultValue( ): AccessorFuncDemoClass | __Name.GetAllowedTypes( ) <class 'str'> | __Name.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
x: 10 | _x: 10 | __x.DefaultValue( ): 1111 | __x.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __x.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
y: 10 | _y: 10 | __y.DefaultValue( ): 2222 | __y.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __y.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
z: 10 | _z: 10 | __z.DefaultValue( ): 3333 | __z.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __z.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Blah: string Blah | _Blah: string Blah | __Blah.DefaultValue( ): <class 'int'> | __Blah.GetAllowedTypes( ) <class 'str'> | __Blah.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Width: False | _Width: False | __Width.DefaultValue( ): 1 | __Width.GetAllowedTypes( ) (<class 'int'>, <class 'bool'>) | __Width.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Height: 9 | _Height: 9 | __Height.DefaultValue( ): 0 | __Height.GetAllowedTypes( ) <class 'int'> | __Height.GetAllowedValues( ) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
Depth: 9 | _Depth: 9 | __Depth.DefaultValue( ): 2 | __Depth.GetAllowedTypes( ) Saved Value Restricted to Authorized Values ONLY | __Depth.GetAllowedValues( ) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
Pamiętaj, że z powodu ograniczonych typów danych lub ograniczeń wartości niektóre dane nie zostały przypisane - jest to zgodne z projektem. Seter zabrania przypisywania złych typów danych lub wartości, nawet przypisywania ich jako wartości domyślnej (chyba że zastąpisz domyślne zachowanie ochrony wartości)
Kod nie został tu opublikowany, ponieważ nie miałem miejsca po przykładach i objaśnieniach ... Również dlatego, że się zmieni.
Uwaga: w momencie tego postu plik jest nieuporządkowany - to się zmieni. Ale jeśli uruchomisz go w Sublime Text i skompilujesz, lub uruchomisz go z Pythona, skompiluje i wypluje mnóstwo informacji - część AccessorDB nie jest gotowa (która zostanie użyta do aktualizacji Print Getters i GetKeyOutput pomocnika funkcje wraz ze zmianą na funkcję Instancji, prawdopodobnie umieszczone w jednej funkcji i zmienione jej nazwy - poszukaj jej ...)
Dalej: Nie wszystko jest wymagane, aby działało - wiele skomentowanych rzeczy na dole zawiera więcej informacji wykorzystywanych do debugowania - może nie być tam podczas pobierania. Jeśli tak, powinieneś być w stanie odkomentować i skompilować ponownie, aby uzyskać więcej informacji.
Szukam obejścia potrzebującego MyClassBase: pass, MyClass (MyClassBase): ... - jeśli znasz rozwiązanie - opublikuj je.
Jedyne, co jest potrzebne w klasie, to wiersze __ - str służy do debugowania, podobnie jak init - można je usunąć z klasy demonstracyjnej, ale trzeba będzie skomentować lub usunąć niektóre z poniższych wierszy (_foo / 2/3 ) ..
Klasy String, Dict i Util u góry są częścią mojej biblioteki Python - nie są kompletne. Skopiowałem kilka rzeczy z biblioteki i stworzyłem kilka nowych. Pełny kod będzie łączył się z pełną biblioteką i będzie ją zawierał wraz z dostarczaniem zaktualizowanych wywołań i usuwaniem kodu (w rzeczywistości jedynym kodem, który pozostanie, będzie klasa demonstracyjna i instrukcje drukowania - system AccessorFunc zostanie przeniesiony do biblioteki). ..
Część pliku:
##
## MyClass Test AccessorFunc Implementation for Dynamic 1-line Parameters
##
class AccessorFuncDemoClassBase( ):
pass
class AccessorFuncDemoClass( AccessorFuncDemoClassBase ):
__Name = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Name', default = 'AccessorFuncDemoClass', allowed_types = ( TYPE_STRING ), allowed_values = VALUE_ANY, documentation = 'Name Docs', getter_prefix = 'Get', key = 'Name', allow_erroneous_default = False, options = { } )
__x = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'X', default = 1111, allowed_types = ( TYPE_INTEGER, TYPE_FLOAT ), allowed_values = VALUE_ANY, documentation = 'X Docs', getter_prefix = 'Get', key = 'x', allow_erroneous_default = False, options = { } )
__Height = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Height', default = 0, allowed_types = TYPE_INTEGER, allowed_values = VALUE_SINGLE_DIGITS, documentation = 'Height Docs', getter_prefix = 'Get', key = 'Height', allow_erroneous_default = False, options = { } )
To piękno sprawia, że niezwykle łatwo jest tworzyć nowe klasy z dynamicznie dodawanymi właściwościami za pomocą AccessorFuncs / callback / data-type / value enforcement itp.
Na razie link znajduje się pod adresem (ten link powinien odzwierciedlać zmiany w dokumencie.): Https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0
Ponadto: jeśli nie używasz Sublime Text, polecam go ponad Notepad ++, Atom, Visual Code i inne ze względu na prawidłowe implementacje wątków, dzięki czemu korzystanie z niego jest znacznie, znacznie szybsze ... Pracuję również nad kodem podobnym do IDE system mapowania dla niego - spójrz na: https://bitbucket.org/Acecool/acecoolcodemappingsystem/src/master/ (najpierw dodaj repozytorium w Menedżerze pakietów, a następnie zainstaluj wtyczkę - gdy wersja 1.0.0 będzie gotowa, dodam do głównej listy wtyczek ...)
Mam nadzieję, że to rozwiązanie pomoże ... i jak zawsze:
Tylko dlatego, że działa, nie robi tego dobrze - Josh „Acecool” Moser
:
i .__init__
self.fn_readyonly