it-swarm-tr.com

Neden açıkça bir Python yönteminde "öz" argümanına ihtiyacınız var?

Python'da bir sınıfta bir yöntem tanımlarken, şuna benzer bir şey görünür:

class MyClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

Ancak, C # gibi diğer bazı dillerde, metodun prototipinde bir argüman olarak ilan etmeden, "this" anahtar kelimesiyle metodun bağlı olduğu nesneye referansınız vardır. 

Bu Python'da kasıtlı bir dil tasarım kararı mıydı yoksa “öz” in argüman olarak geçmesini gerektiren bazı uygulama detayları var mı?

180
Readonly

Peters 'Zen of Python'dan alıntı yapmayı severim. "Açık, örtük olmaktan iyidir."

Java ve C++, 'this.' ifadesi, çıkarılmasını imkansız kılan değişken isimleriniz olması haricinde düşülebilir. Yani bazen ihtiyacın olur ve bazen ihtiyacın olmaz.

Python, bir kurala dayanmak yerine, bu gibi şeyleri açıkça ortaya koymayı seçer. 

Ek olarak, hiçbir şey ima edilmediğinden veya varsayılmadığından, uygulamanın bazı kısımları ortaya çıkar. self.__class__, self.__dict__ ve diğer "dahili" yapılar açık bir şekilde kullanılabilir.

88
S.Lott

Metotlar ve fonksiyonlar arasındaki farkı minimize etmek. Metasınıflarda kolayca yöntem üretmenizi veya önceden var olan sınıflara çalışma zamanında yöntemler eklemenizi sağlar.

Örneğin.

>>> class C(object):
...     def foo(self):
...         print "Hi!"
...
>>>
>>> def bar(self):
...     print "Bork bork bork!"
...
>>>
>>> c = C()
>>> C.bar = bar
>>> c.bar()
Bork bork bork!
>>> c.foo()
Hi!
>>>

Ayrıca (bildiğim kadarıyla) python çalışma zamanının uygulanmasını kolaylaştırıyor.

55
Ryan

Birinin Guido van Rossum'un bu konudaki blogunu okumasını öneririm - Açık öz benliğin kalması .

Bir metot tanımı dekore edildiğinde, otomatik olarak bir 'self' parametresi verilip verilmeyeceğini bilmiyoruz: dekoratör fonksiyonu statik bir yönteme ('öz' olmayan) veya sınıf yöntemine dönüştürebilir. bir örnek yerine bir sınıfa atıfta bulunan komik bir öz benliği vardır) ya da tamamen farklı bir şey yapabilir (saf Python'da 'classmethod' veya 'staticmethod' uygulayan bir dekoratör yazmak önemsizdir). Dekoratörün, “gizli” bir argümanla tanımlanan yönteme sahip olup olmadığına sahip olup olmadığını bilmeden hiçbir yolu yoktur.

Özel kasetli '@classmethod' ve 'staticmethod' gibi saldırıları reddediyorum.

51
bhadra

Python sizi "kendini" kullanmaya zorlamaz. İstediğin ismi verebilirsin. Sadece bir metod tanımı başlığındaki ilk argümanın nesneye referans olduğunu hatırlamanız gerekir.

16
Victor Noagbodji

Ayrıca bunu yapmanıza izin verir: (kısacası, Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5) işlevini çağırmak 12 döndürür, ancak bunu en çılgın şekillerde yapar.

class Outer(object):
    def __init__(self, outer_num):
        self.outer_num = outer_num

    def create_inner_class(outer_self, inner_arg):
        class Inner(object):
            inner_arg = inner_arg
            def weird_sum_with_closure_scope(inner_self, num)
                return num + outer_self.outer_num + inner_arg
        return Inner

Tabii ki, Java ve C # gibi dillerde hayal etmek daha zordur. Kendi kendine referansı açık yaparak, bu kendi kendine referansla herhangi bir nesneye başvurmakta özgürsünüz. Ayrıca, çalışma zamanında sınıflarla oynamanın böyle bir yolu daha statik dillerde yapmak zordur - bu mutlaka iyi ya da kötü değil. Sadece açık benlik tüm bu çılgınlığın var olmasına izin veriyor.

Dahası, şunu hayal edin: Yöntemlerin davranışını özelleştirmek istiyoruz (profil oluşturma veya çılgın bir kara büyü için). Bu bize şu düşünceyi doğurabilir: peki ya davranışını yenebilecek ya da kontrol edebileceğimiz Method sınıfımız varsa?

Peki burada:

from functools import partial

class MagicMethod(object):
    """Does black magic when called"""
    def __get__(self, obj, obj_type):
        # This binds the <other> class instance to the <innocent_self> parameter
        # of the method MagicMethod.invoke
        return partial(self.invoke, obj)


    def invoke(magic_self, innocent_self, *args, **kwargs):
        # do black magic here
        ...
        print magic_self, innocent_self, args, kwargs

class InnocentClass(object):
    magic_method = MagicMethod()

Ve şimdi: InnocentClass().magic_method() beklendiği gibi davranacak. Yöntem, innocent_self parametresiyle InnocentClass öğesine ve magic_self ile MagicMethod örneğine bağlanacaktır. Garip değil mi? Java ve C # gibi dillerde 2 anahtar kelime this1 ve this2 olması gibi. Bunun gibi bir sihir, çerçevelerin aksi takdirde çok daha ayrıntılı olacak şeyler yapmasına izin verir.

Yine, bu şeylerin etiği hakkında yorum yapmak istemiyorum. Sadece açık bir öz referans olmadan yapması zor olan şeyleri göstermek istedim.

6
vlad-ardelean

"Python'un Zen'i" nin yanı sıra asıl sebep, İşlevlerin Python'da birinci sınıf vatandaşlar olmasıdır. 

Bu aslında onları bir nesne yapar. Şimdi Temel sorun, eğer işlevleriniz aynı zamanda nesne ise, Nesne yönelimli paradigmada, mesajların kendisi nesneler olduğunda Nesnelere nasıl mesaj gönderirsiniz? 

Tavuk gibi gözüküyor Yumurta problemi, bu paradoksu azaltmak için, mümkün olan tek yol, yöntemlerin uygulanma bağlamını geçmek ya da tespit etmektir. Ancak python iç içe geçmiş işlevlere sahip olabileceğinden, yürütme bağlamı iç işlevler için değişeceği için bunu yapmak imkansız olacaktır. 

Bu, mümkün olan tek çözümün açıkça 'özden' geçilmesidir (yürütme bağlamı).

Bu yüzden Zen'in daha sonra geldiği bir uygulama problemi olduğuna inanıyorum.

2
pankajdoharey

PEP 227 ile bir ilgisi olduğunu düşünüyorum:

Sınıf kapsamındaki isimler erişilebilir değildir. İsimler isminde çözüldü. en içteki çevreleme işlevi kapsamı. Bir sınıf tanımı a .__ 'da meydana gelirse. iç içe kapsamlar zinciri, çözümleme işlemi sınıf .__ atlar. tanımlar. Bu kural, sınıf .__ arasındaki garip etkileşimleri önler. özellikler ve yerel değişken erişimi. Bir isim ciltleme işlemi ise. Bir sınıf tanımında ortaya çıkar, sonuçta elde edilen .__ üzerinde bir öznitelik oluşturur. sınıf nesnesi Bu değişkene bir yöntemde veya işlevde erişmek için Bir yöntemin içine yerleştirilmiş bir öznitelik başvurusu kullanılmalıdır, ya kendini veya sınıf adını kullanarak.

2
daole

Python'da benlikte açıklandığı gibi, Demystified

obj.meth (args) gibi bir şey Class.meth (obj, args) olur. Alma işlemi değilken (açık) çağıran süreç otomatiktir. Bu, sınıftaki bir işlevin ilk parametresinin nesnenin kendisi olmasının nedeni budur. 

class Point(object):
    def __init__(self,x = 0,y = 0):
        self.x = x
        self.y = y

    def distance(self):
        """Find distance from Origin"""
        return (self.x**2 + self.y**2) ** 0.5

Invocations:

>>> p1 = Point(6,8)
>>> p1.distance()
10.0

init () üç parametre tanımlar, ancak iki tane geçtik (6 ve 8). Benzer şekilde distance () bir tane gerektirir ancak sıfır argümanlar iletildi. 

Python neden bu argüman numarası uyumsuzluğundan şikayet etmiyor?

Genellikle, bazı argümanlarla bir yöntem çağırdığımızda, karşılık gelen sınıf işlevi, yöntemin nesnesini ilk argümandan önce yerleştirerek çağrılır. Böylece, obj.meth (args) gibi bir şey Class.meth (obj, args) olur. Arama işlemi otomatik iken alım işlemi otomatik değil (açık).

Bu, sınıftaki bir işlevin ilk parametresinin nesnenin kendisi olmasının nedeni budur. Bu parametrenin benlik olarak yazılması yalnızca bir kuraldır. Anahtar kelime değildir ve Python'da özel bir anlamı yoktur. Başka isimler de kullanabiliriz (bunun gibi) ama kesinlikle söylememenizi tavsiye ederim. Kendinden başka isimler kullanmak çoğu geliştirici tarafından kaşlarını çattı ve kodun okunabilirliğini ("Okunabilirlik sayar") düşürür. 
...
İlk örnekte, self.x bir örnek niteliğidir, oysa x yerel bir değişkendir. Aynı değillerdir ve farklı ad alanlarında yalan söylerler.

Öz kalmak için burada

Birçoğu, C = ve Java'da olduğu gibi 'in kendini Python'da bir anahtar kelime yapmasını önerdi. Bu, açık kendi kendine gereksiz kullanımın, metotlardaki parametre listesinden kullanılmasını ortadan kaldıracaktır. Bu fikir ümit verici görünse de, olmayacak. En azından yakın gelecekte. Asıl sebep geriye dönük uyumluluktur. İşte Python'un yaratıcısından, açık benliğin neden kalması gerektiğini açıklayan bir blog.

0
mon