2009-03-11 16 views
12

प्रश्न "How can I monkey-patch an instance method in Perl?" मुझे सोचने लगा। क्या मैं गतिशील रूप से पर्ल विधियों को फिर से परिभाषित कर सकता हूं?मैं पर्ल क्लास विधियों को फिर से परिभाषित कैसे कर सकता हूं?

package MyClass; 
sub new { 
    my $class = shift; 
    my $val = shift; 
    my $self = { val=> $val}; 

    bless($self, $class); 
    return $self; 
}; 

sub get_val { 
    my $self = shift; 
    return $self->{val}+10; 
} 
1; 

और कहते हैं कि दो नंबर जोड़ने वास्तव में महंगा है चलो: मैं इस तरह एक वर्ग है कहो।

मैं कक्षा को संशोधित करना चाहता हूं ताकि $ val + 10 केवल उस वस्तु पर विधि को कॉल करने पर पहली बार गणना की जाए। विधि के बाद के कॉल एक कैश मूल्य लौटाएंगे।

मैं आसानी से कैशिंग शामिल करने के लिए विधि को संशोधित सकता है, लेकिन:

  • मैं इस तरह के तरीकों का एक समूह है।
  • मैं इस विधि को गंदे नहीं करना चाहता हूं।

जो मैं वास्तव में करना चाहता हूं वह उन तरीकों की एक सूची निर्दिष्ट करता है जो मुझे पता है कि किसी दिए गए उदाहरण के लिए हमेशा एक ही मान वापस आते हैं। मैं फिर इस सूची को लेना चाहता हूं और उन तरीकों को कैशिंग समर्थन जोड़ने के लिए इसे एक समारोह में भेजना चाहता हूं

क्या इसे पूरा करने का कोई प्रभावी तरीका है?

फ़ॉलो करें। नीचे दिया गया कोड काम करता है, लेकिन क्योंकि सख्त उपयोग स्ट्रिंग द्वारा संदर्भों की अनुमति नहीं देता है, मैं 100% नहीं हूं जहां मैं बनना चाहता हूं।

sub myfn { 
    printf("computing\n"); 
    return 10; 
} 
sub cache_fn { 
    my $fnref = shift; 

    my $orig = $fnref; 
    my $cacheval; 

    return sub { 
    if (defined($cacheval)) { return $cacheval; } 
    $cacheval = &$orig(); 
    return $cacheval; 
    } 
} 

*{myfn} = cache_fn(\&myfn); 

कैसे मैं सिर्फ इस ?:

cache_fn(&myfn); 
+0

{कोई चेतावनी 'redefine' नहीं; * myfn = cache_fn (\ &myfn);} - यह संदिग्ध और चेतावनी को फिर से परिभाषित करने से छुटकारा पाता है। cache_fn (&myfn); – draegtun

+0

) के बारे में मेरा नया उत्तर देखें, आप यादों को देखना चाहते हैं (कुछ अच्छे सीपीएएन मॉड्यूल हैं), या महंगे कैश करने के लिए मूस ट्रिगर्स का उपयोग करना विशेषताओं में संगणना और उन्हें के रूप में चलाता साथ की जरूरत पुनर्गणना – Ether

उत्तर

11

आप इस तरह एक और पैकेज से get_val तरह के तरीकों के ऊपर लिख सकते हैं करने के लिए संपादित कर सकता:

*{MyClass::get_val} = sub { return $some_cached_value }; 

आप विधि की एक सूची है, तो नाम, आप ऐसा कुछ कर सकते हैं:

my @methods = qw/ foo bar get_val /; 
foreach my $meth (@methods) { 
    my $method_name = 'MyClass::' . $meth; 
    no strict 'refs'; 
    *{$method_name} = sub { return $some_cached_value }; 
} 

क्या आप कल्पना करते हैं?

+0

उपयोग सख्त;।। मुझे स्ट्रिंग द्वारा कार्यों का उल्लेख करने की अनुमति नहीं है वहाँ एक रास्ता यह चारों ओर पाने के लिए है सुरक्षित रूप से – mmccoo

+1

आप एक तरीका है कि उपयोग नहीं करता है "कोई सख्त 'refs मतलब है? '' मेरे दूसरे उदाहरण की तरह? कोई भी जिसे मैं जानता हूं। – innaM

3

मैंने कभी भी विधियों के साथ प्रयास नहीं किया है, लेकिन Memoize जो भी आप खोज रहे हैं वह हो सकता है। लेकिन caveats को पढ़ना सुनिश्चित करें।

+0

यह विधियों के साथ काम करेगा, लेकिन अगर आप सभी उदाहरणों में कैश करना चाहते हैं तो आपको NORMALIZER विकल्प का उपयोग करना पड़ सकता है। यदि आप प्रति उदाहरण कैश करना चाहते हैं, तो शायद यह संभवतः है आसान सिर्फ वस्तु में मूल्य, जैसे वापसी $ स्वयं रहना -> {foo} मौजूद रहने पर $ आत्म -> {foo} – runrig

+0

आसान आप वें लिख रहे हैं, तो है कि ई कक्षा सवाल का तात्पर्य है कि वह उस वर्ग को गतिशील रूप से संशोधित करने की कोशिश कर रहा है जिसे उसने नहीं लिखा था। – cjm

2

अपने मामले में उपयोगी नहीं है, लेकिन अपने वर्ग Moose में लिखा गया था तो आप गतिशील रूप से अपने Class::MOP आधार का उपयोग कर तरीकों ओवरराइड कर सकते हैं ....

{ 
    package MyClass; 
    use Moose; 

    has 'val' => (is => 'rw'); 

    sub get_val { 
     my $self = shift; 
     return $self->val + 10; 
    } 

} 

my $A = MyClass->new(val => 100); 
say 'A: before: ', $A->get_val; 

$A->meta->remove_method('get_val'); 
$A->meta->add_method('get_val', sub { $_[0]->val }); 

say 'A: after: ', $A->get_val; 

my $B = MyClass->new(val => 100); 
say 'B: after: ', $B->get_val; 

# gives u... 
# => A: before: 110 
# => A: after: 100 
# => B: after: 100 
2

कैसे मैं सिर्फ यह करने के लिए संपादित कर सकता ?:

cache_fn (\ & myfn);

खैर अपने वर्तमान उदाहरण के आधार पर आप कुछ इस तरह कर सकता है ....

sub cache_fn2 { 
    my $fn_name = shift; 
    no strict 'refs'; 
    no warnings 'redefine'; 

    my $cache_value = &{ $fn_name }; 
    *{ $fn_name } = sub { $cache_value }; 
} 

cache_fn2('myfn'); 

हालांकि इस उदाहरण मैं सोच आप Memoize बजाय इस्तेमाल कर सकते हैं कि मदद नहीं कर सकता को देखकर?

5

मैं कई अलग अलग चीजें आप Mastering Perl की "गतिशील सबरूटीन्स" अध्याय में क्या करना चाहते हो सकता है के बारे में लिखें। तुम क्या कर रहे आधार पर, आप सबरूटीन लपेट, या यह, या उपवर्ग, या अन्य चीजों के सभी प्रकार को फिर से परिभाषित करने के लिए चाहते हो सकता है।

पर्ल एक गतिशील भाषा है, इसलिए वहां बहुत सारे काले जादू हैं जो आप कर सकते हैं। बुद्धिमानी से इसका उपयोग करना चाल है।

+1

लिंक के लिए धन्यवाद। मैंने ऑनलाइन कुछ पेज पढ़े और उन्हें यह जवाब देने के लिए जो चाहिए वह मिल गया। लग रहा है एक और किताब की तरह मेरे खरीदारी की सूची पर है। – mmccoo

संबंधित मुद्दे

 संबंधित मुद्दे