تزين بايثون فئة لتغيير نوع الكائن الأصلي
-
05-07-2019 - |
سؤال
لنفترض أن لديك فئتين X و Y.تريد تزيين تلك الفئات عن طريق إضافة سمات إلى الفصل لإنتاج فئات جديدة X1 وY1.
على سبيل المثال:
class X1(X):
new_attribute = 'something'
class Y1(Y):
new_attribute = 'something'
new_attribute سيكون دائمًا هو نفسه لكل من X1 وY1.لا يرتبط X وY بأي طريقة ذات معنى، باستثناء أن الميراث المتعدد غير ممكن.هناك مجموعة من السمات الأخرى أيضًا، لكن هذا منحط للتوضيح.
أشعر وكأنني أبالغ في تعقيد هذا الأمر، لكنني فكرت في استخدام أحد مصممي الديكور، إلى حد ما:
def _xywrap(cls):
class _xy(cls):
new_attribute = 'something'
return _xy
@_xywrap(X)
class X1():
pass
@_xywrap(Y)
class Y1():
pass
يبدو الأمر وكأنني أفتقد نمطًا شائعًا إلى حد ما، وسأكون ممتنًا جدًا للأفكار والمدخلات والتعليقات.
شكرا لقرائتك.
بريان
يحرر: مثال:
فيما يلي مقتطف ذو صلة قد يضيء.الطبقات المشتركة هي كما يلي:
from google.appengine.ext import db
# I'm including PermittedUserProperty because it may have pertinent side-effects
# (albeit unlikely), which is documented here: [How can you limit access to a
# GAE instance to the current user][1].
class _AccessBase:
users_permitted = PermittedUserProperty()
owner = db.ReferenceProperty(User)
class AccessModel(db.Model, _AccessBase):
pass
class AccessExpando(db.Expando, _AccessBase):
pass
# the order of _AccessBase/db.* doesn't seem to resolve the issue
class AccessPolyModel(_AccessBase, polymodel.PolyModel):
pass
إليك مستند فرعي:
class Thing(AccessExpando):
it = db.StringProperty()
في بعض الأحيان سيكون لدى الشيء الخصائص التالية:
Thing { it: ... }
وأوقات أخرى:
Thing { it: ..., users_permitted:..., owner:... }
لم أتمكن من معرفة سبب احتواء Thing في بعض الأحيان على خصائص _AccessParent الخاصة به، وفي أحيان أخرى لا.
المحلول
استخدم 3-الحجج يكتب:
def makeSomeNicelyDecoratedSubclass(someclass):
return type('MyNiceName', (someclass,), {'new_attribute':'something'})
وهذا بالفعل، كما خمنت، لغة شعبية إلى حد معقول.
يحرر:في الحالة العامة، إذا كانت إحدى الفئات تحتوي على فئة تعريفية مخصصة، فقد تحتاج إلى استخراجها واستخدامها (مع وسيطة واحدة type
) بدلا من type
نفسه، للحفاظ عليه (قد يكون هذا هو الحال بالنسبة لنماذج Django وApp Engine):
def makeSomeNicelyDecoratedSubclass(someclass):
mcl = type(someclass)
return mcl('MyNiceName', (someclass,), {'new_attribute':'something'})
يعمل هذا أيضًا حيث يعمل الإصدار الأبسط أعلاه (نظرًا لأنه في الحالات البسيطة بدون فئات تعريفية مخصصة type(someclass) is type
).
نصائح أخرى
الرد على تعليقاتكم على إجابة المسافر:
from google.appengine.ext import db
class Mixin(object):
"""Mix in attributes shared by different types of models."""
foo = 1
bar = 2
baz = 3
class Person(db.Model, Mixin):
name = db.StringProperty()
class Dinosaur(db.polymodel.PolyModel, Mixin):
height = db.IntegerProperty()
p = Person(name='Buck Armstrong, Dinosaur Hunter')
d = Dinosaur(height=5000)
print p.name, p.foo, p.bar, p.baz
print d.height, d.foo, d.bar, d.baz
تشغيل يؤدي إلى
Buck Armstrong, Dinosaur Hunter 1 2 3
5000 1 2 3
أليس هذا ما كان يدور في ذهنك؟
لماذا لا يمكنك استخدام ميراث متعدد?
class Origin:
new_attribute = 'something'
class X:
pass
class Y:
pass
class X1(Origin, X):
pass
class Y1(Origin, Y):
pass