it-swarm-tr.com

Maymun yama nedir?

Anlamaya çalışıyorum, maymun yama mı yoksa maymun yama mı?

Metot/operatörlerin aşırı yüklenmesi mi yoksa delegasyonu gibi bir şey mi?

Bunlarla ortak bir yanı var mı?

462
Sergei Basharov

Hayır, bunların hiçbiri gibi değil. Bu sadece çalışma zamanında niteliklerin dinamik değiştirilmesidir.

Örneğin, get_data yöntemi olan bir sınıfı düşünün. Bu yöntem harici bir arama yapar (örneğin bir veritabanında veya web API'sinde) ve sınıftaki diğer çeşitli yöntemler bunu çağırır. Bununla birlikte, bir birim testinde, harici veri kaynağına bağımlı olmak istemezsiniz - bu yüzden get_data yöntemini dinamik olarak bazı sabit veriler veren bir saplama ile değiştirirsiniz.

Python sınıfları değişkendir ve yöntemler yalnızca sınıfın öznitelikleri olduğundan, bunu istediğiniz kadar yapabilirsiniz - ve hatta, bir modüldeki sınıfları ve işlevleri aynı şekilde değiştirebilirsiniz.

Ancak, bir yorumc işaret ettiğine göre, maymun yakalarken dikkatli olun:

  1. Test mantığınızdan başka herhangi bir şey get_data'yi de çağırırsa, orijinal yerine maymun yamalı değiştirme işlevinizi de çağırır - ki bu iyi veya kötü olabilir. Sadece dikkat et.

  2. Değiştirdiğiniz zaman da get_data işlevine işaret eden bir değişken veya özellik varsa, bu takma ad anlamını değiştirmez ve orijinal get_data işaretini vermeye devam eder. (Neden? Python, sınıfınızdaki get_data adını başka bir işlev nesnesine yeniden bağlar; diğer ad bağlantıları hiç etkilenmez.)

450
Daniel Roseman

MonkeyPatch, çalışma zamanında (genellikle başlangıçta) diğer kodu genişleten veya değiştiren bir Python kodu parçasıdır.

Basit bir örnek şöyle görünür:

from SomeOtherProduct.SomeModule import SomeClass

def speak(self):
    return "ook ook eee eee eee!"

SomeClass.speak = speak

Kaynak: MonkeyPatch = Zope wiki'deki sayfa.

339
Paolo

Maymun yama nedir?

Basitçe söylemek gerekirse, maymun eklemesi, program çalışırken bir modülde veya sınıfta değişiklikler yapıyor.

Kullanımdaki örnek

Panda'nın belgelerinde maymun yamalarının bir örneği var:

import pandas as pd
def just_foo_cols(self):
    """Get a list of column names containing the string 'foo'

    """
    return [x for x in self.columns if 'foo' in x]

pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method

Bunu yıkmak için önce modülümüzü içe aktarıyoruz:

import pandas as pd

Daha sonra, herhangi bir sınıf tanımının kapsamı dışında, sınırsız ve serbest bir yöntem tanımı oluşturacağız (ayrım, bir işlev ile bir sınırsız yöntem arasında oldukça anlamsız olduğu için, Python 3, sınırlanmamış yöntemle ortadan kalkar):

def just_foo_cols(self):
    """Get a list of column names containing the string 'foo'

    """
    return [x for x in self.columns if 'foo' in x]

Daha sonra bu yöntemi üzerinde kullanmak istediğimiz sınıfa ekleriz:

pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class

Ve sonra metodu sınıfın bir örneğinde kullanabiliriz ve bittiğinde yöntemi silebiliriz:

df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method

İsim yönetimi için uyarı

Name-mangling kullanıyorsanız (çift alt çizgi içeren önekleme özellikleri, adı değiştiren ve önermediğim), bunu yaparsanız manuel olarak adlandırma yapmanız gerekir. İsim yönetimi önermediğim için, burada göstermeyeceğim.

Test örneği

Bu bilgiyi örneğin testlerde nasıl kullanabiliriz?

Diyelim ki, bir hatayla sonuçlanan harici bir veri kaynağına veri alma çağrısı simüle etmemiz gerekiyor, çünkü böyle bir durumda doğru davranışı sağlamak istiyoruz. Bu davranışı sağlamak için veri yapısını yamalayabiliriz. (Yani Daniel Roseman tarafından önerilen benzer bir yöntem adı kullanarak :)

import datasource

def get_data(self):
    '''monkey patch datasource.Structure with this to simulate error'''
    raise datasource.DataRetrievalError

datasource.Structure.get_data = get_data

Ve bu yönteme dayanan davranışları test ederken hataya yol açıyorsak, doğru şekilde uygulanırsa, bu davranışı test sonuçlarında elde ederiz.

Yukarıdakileri yapmanız, işlemin ömrü boyunca Structurenesnesini değiştirecektir; bu nedenle, bunu yapmaktan kaçınmak için en küçüklerinizde kurulumları ve gözyaşıları kullanmak isteyeceksiniz, örn .:

def setUp(self):
    # retain a pointer to the actual real method:
    self.real_get_data = datasource.Structure.get_data
    # monkey patch it:
    datasource.Structure.get_data = get_data

def tearDown(self):
    # give the real method back to the Structure object:
    datasource.Structure.get_data = self.real_get_data

(Yukarıdakiler iyi olsa da, muhtemelen kodu düzeltmek için mockkütüphanesini kullanmak daha iyi bir fikir olacaktır. mockname __ 'in patchdekoratörü, yukarıdaki kodları yapmaktan daha az hataya neden olur ve bu da daha fazla kod satırı gerektirecek ve bu nedenle daha fazla kod satırına giriş yapacaktır. Hatalar. Henüz kodu mockdosyasında gözden geçirmedim, ancak benzer şekilde maymun yamalamasını kullandığını hayal ediyorum.)

103
Aaron Hall

Wikipedia'ya göre :

Python'da maymun yaması terimi, yalnızca çalışma zamanında bir sınıfın veya modülün dinamik değişikliklerini ifade eder, var olan üçüncü taraf kodunu istediğiniz gibi bir hata ya da özelliğe geçici bir çözüm olarak ekleme niyetiyle motive edilir.

25
David Heffernan

İlk: maymun yama, kötü bir kesmektir (bence).

Genellikle modül veya sınıf seviyesindeki bir yöntemi özel bir uygulamayla değiştirmek için kullanılır.

En yaygın usecase, orijinal kodu değiştiremediğiniz zaman bir modül veya sınıftaki bir hata için geçici bir çözüm ekliyor. Bu durumda, "yanlış" kodunu, kendi modülünüz/paketinizin içindeki bir uygulamayla maymun eklemesi yoluyla değiştirirsiniz.

17
Andreas Jung

Maymun yama sadece Python'un iyi bir örnek olduğu dinamik dillerde yapılabilir. Nesne tanımını güncellemek yerine çalışma zamanında bir yöntemi değiştirmek bir örnektir; benzer şekilde, çalışma zamanında nitelikler (yöntemler veya değişkenler eklemek) maymun eklemesi olarak kabul edilir. Bunlar genellikle kaynağınız olmayan modüllerle çalışırken, nesne tanımlarının kolayca değiştirilemeyeceği şekilde yapılır.

Bu kötü olarak kabul edilir, çünkü bir nesnenin tanımının gerçekte nasıl davrandığını tam veya doğru olarak tanımlayamadığı anlamına gelir.

12
Aaron Dufour

Maymun yama, mevcut sınıfları veya sınıfları çalışma zamanında sınıf içinde yeniden açıyor ve dikkatli kullanılması gereken davranışı değiştiriyor ya da sadece gerçekten ihtiyacınız olduğunda kullanmalısınız.

Python dinamik bir programlama dili olduğundan, Sınıflar değişkendir, böylece onları yeniden açabilir ve değiştirebilir veya hatta değiştirebilirsiniz.

4
kamal