كيف يمكنني ببساطة أن أرث الأساليب من مثيل موجود؟
-
09-06-2019 - |
سؤال
أدناه لدي مثال بسيط جدًا لما أحاول القيام به.أريد أن أكون قادرًا على استخدام HTMLDecorator مع أي فئة أخرى.تجاهل حقيقة أنه يسمى مصمم الديكور، إنه مجرد اسم.
import cgi
class ClassX(object):
pass # ... with own __repr__
class ClassY(object):
pass # ... with own __repr__
inst_x=ClassX()
inst_y=ClassY()
inst_z=[ i*i for i in range(25) ]
inst_b=True
class HTMLDecorator(object):
def html(self): # an "enhanced" version of __repr__
return cgi.escape(self.__repr__()).join(("<H1>","</H1>"))
print HTMLDecorator(inst_x).html()
print HTMLDecorator(inst_y).html()
wrapped_z = HTMLDecorator(inst_z)
inst_z[0] += 70
wrapped_z[0] += 71
print wrapped_z.html()
print HTMLDecorator(inst_b).html()
انتاج:
Traceback (most recent call last): File "html.py", line 21, in print HTMLDecorator(inst_x).html() TypeError: default __new__ takes no parameters
هل ما أحاول فعله ممكن؟إذا كان الأمر كذلك، ما الخطأ الذي أفعله؟
المحلول
قريب جدًا، ولكن بعد ذلك أفقد كل شيء من ClassX.يوجد أدناه شيء أعطاني إياه أحد الزملاء وهو يفي بالغرض، لكنه بشع.حتما توجد طريقة افضل.
يبدو أنك تحاول إعداد نوع من نظام كائن الوكيل.وهذا أمر ممكن التنفيذ، وهناك حلول أفضل من حلول زميلك، ولكن فكر أولاً فيما إذا كان من الأسهل مجرد تصحيح بعض الطرق الإضافية.لن يعمل هذا مع الفصول المضمنة مثل bool
, ، ولكنه سيفعل ذلك بالنسبة للفصول الدراسية المحددة من قبل المستخدم:
def HTMLDecorator (obj):
def html ():
sep = cgi.escape (repr (obj))
return sep.join (("<H1>", "</H1>"))
obj.html = html
return obj
وهنا نسخة الوكيل:
class HTMLDecorator(object):
def __init__ (self, wrapped):
self.__wrapped = wrapped
def html (self):
sep = cgi.escape (repr (self.__wrapped))
return sep.join (("<H1>", "</H1>"))
def __getattr__ (self, name):
return getattr (self.__wrapped, name)
def __setattr__ (self, name, value):
if not name.startswith ('_HTMLDecorator__'):
setattr (self.__wrapped, name, value)
return
super (HTMLDecorator, self).__setattr__ (name, value)
def __delattr__ (self, name):
delattr (self.__wraped, name)
نصائح أخرى
كلا الحلين اللذين طرحهما جون سيعملان.هناك خيار آخر يسمح لـ HTMLDecorator بالبقاء بسيطًا ونظيفًا للغاية وهو تصحيحه كفئة أساسية.يعمل هذا أيضًا مع الفئات المعرفة من قبل المستخدم فقط، وليس الأنواع المضمنة:
import cgi
class ClassX(object):
pass # ... with own __repr__
class ClassY(object):
pass # ... with own __repr__
inst_x=ClassX()
inst_y=ClassY()
class HTMLDecorator:
def html(self): # an "enhanced" version of __repr__
return cgi.escape(self.__repr__()).join(("<H1>","</H1>"))
ClassX.__bases__ += (HTMLDecorator,)
ClassY.__bases__ += (HTMLDecorator,)
print inst_x.html()
print inst_y.html()
كن حذرًا، على الرغم من ذلك - فإن التصحيح القردي مثل هذا يأتي بثمن باهظ من حيث سهولة القراءة وقابلية الصيانة للتعليمات البرمجية الخاصة بك.عندما تعود إلى هذا الرمز بعد عام، قد يصبح من الصعب للغاية معرفة كيف حصل ClassX على طريقة html()، خاصة إذا تم تعريف ClassX في بعض المكتبات الأخرى.
هل ما أحاول فعله ممكن؟إذا كان الأمر كذلك، ما الخطأ الذي أفعله؟
من الممكن بالتأكيد.ما هو الخطأ في ذلك HTMLDecorator.__init__()
لا يقبل المعلمات
إليك مثال بسيط:
def decorator (func):
def new_func ():
return "new_func %s" % func ()
return new_func
@decorator
def a ():
return "a"
def b ():
return "b"
print a() # new_func a
print decorator (b)() # new_func b
@ جون (37448):
آسف، ربما خدعتك بالاسم (اختيار سيء).أنا لا أبحث حقًا عن وظيفة ديكور، أو أي شيء يتعلق بالديكور على الإطلاق.ما أسعى إليه هو أن يستخدم html(self) def استخدام ClassX أو ClassY's __repr__
.أريد أن يعمل هذا دون تعديل ClassX أو ClassY.
آه، في هذه الحالة، ربما يكون رمز مثل هذا مفيدًا؟ليس له أي علاقة بالديكورات، ولكنه يوضح كيفية تمرير الوسائط إلى وظيفة تهيئة الفصل واسترداد تلك الوسائط لوقت لاحق.
import cgi
class ClassX(object):
def __repr__ (self):
return "<class X>"
class HTMLDecorator(object):
def __init__ (self, wrapped):
self.__wrapped = wrapped
def html (self):
sep = cgi.escape (repr (self.__wrapped))
return sep.join (("<H1>", "</H1>"))
inst_x=ClassX()
inst_b=True
print HTMLDecorator(inst_x).html()
print HTMLDecorator(inst_b).html()
@ جون (37479):
قريب جدًا، ولكن بعد ذلك أفقد كل شيء من ClassX.يوجد أدناه شيء أعطاني إياه أحد الزملاء وهو يفي بالغرض، ولكنه بشع.حتما توجد طريقة افضل.
import cgi
from math import sqrt
class ClassX(object):
def __repr__(self):
return "Best Guess"
class ClassY(object):
pass # ... with own __repr__
inst_x=ClassX()
inst_y=ClassY()
inst_z=[ i*i for i in range(25) ]
inst_b=True
avoid="__class__ __init__ __dict__ __weakref__"
class HTMLDecorator(object):
def __init__(self,master):
self.master = master
for attr in dir(self.master):
if ( not attr.startswith("__") or
attr not in avoid.split() and "attr" not in attr):
self.__setattr__(attr, self.master.__getattribute__(attr))
def html(self): # an "enhanced" version of __repr__
return cgi.escape(self.__repr__()).join(("<H1>","</H1>"))
def length(self):
return sqrt(sum(self.__iter__()))
print HTMLDecorator(inst_x).html()
print HTMLDecorator(inst_y).html()
wrapped_z = HTMLDecorator(inst_z)
print wrapped_z.length()
inst_z[0] += 70
#wrapped_z[0] += 71
wrapped_z.__setitem__(0,wrapped_z.__getitem__(0)+ 71)
print wrapped_z.html()
print HTMLDecorator(inst_b).html()
انتاج:
<H1>Best Guess</H1> <H1><__main__.ClassY object at 0x891df0c></H1> 70.0 <H1>[141, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576]</H1> <H1>True</H1>