Python'da “sınıf yöntemleri” ve “örnek yöntemleri” nedir?


37

Sohbette, bir soru ile ilgili bir tartışma oldu (sorunun kendisi bununla ilgisiz), Python'u hiçbir şekilde bilemeyeceğimi açıkladı.

Aklımda, terminoloji diller arasında farklılık gösterse de, işlevleri genel olarak şu şekilde kategorize edebiliriz:

  • [free] fonksiyonlar
  • statik yöntemler / statik üye fonksiyonları
  • statik olmayan yöntemler / statik olmayan üye fonksiyonlar

Görünüşe göre Python'da yukarıdaki kategorilere uymayan başka bir tür işlev var, biri yöntem, ancak "sınıfını bilmiyor".

Python'da "sınıf yöntemleri" ve "örnek yöntemleri" nedir?


1
Sohbet tartışmasıyla ilgilenen varsa, buradan başlayın: chat.stackexchange.com/transcript/message/26479002#26479002
yannis

1
IMO farklı bir stackexchange web sitesi tarafından daha iyi bir cevap
Trevor Boyd Smith

Bilginize bağlantı kabul edilen dibinde verilir ... ama bence birçok kişi bağlantıyı özleyemez veya asla alamaz ve bu yüzden buraya kopyaladım.
Trevor Boyd Smith

Yanıtlar:


49

Kısa cevap

  • bir örnek yöntemi kendi örneğini bilir (ve ondan da sınıfı)
  • Bir sınıf yöntemi sınıfını bilir
  • statik bir yöntem sınıfını veya örneğini bilmiyor

Uzun cevap

Sınıf yöntemleri

Bir sınıf yöntemi , bir bütün olarak sınıfa ait olan yöntemdir . Örnek gerektirmez. Bunun yerine, sınıf otomatik olarak ilk argüman olarak gönderilir. @classmethodDekoratör ile bir sınıf metodu ilan edilir .

Örneğin:

class Foo(object):
    @classmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)
Foo.hello()
-> "Hello from Foo"
Foo().hello()
-> "Hello from Foo"

Örnek Yöntemleri

Öte yandan, bir örnek yöntemi onu çağırmak için bir örnek gerektirir ve dekoratör gerektirmez. Bu, şu ana kadar en yaygın yöntem türüdür.

class Foo(object):
    def hello(self):
        print("hello from %s" % self.__class__.__name__)
Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'self'

(not: yukarıdaki python3'tür; python2 ile biraz farklı bir hata alırsınız)

Statik yöntemler

Bir statik yöntem , bir sınıf yönteme benzer, ancak otomatik bir parametre olarak sınıf nesnesi olmayacak. @staticmethodDekoratör kullanılarak oluşturulur .

class Foo(object):
    @staticmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)

Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'cls'

Belge bağlantıları

İlgili python3 belgeseline bağlantılar:

Veri modeli dokümantasyon sınıf yöntemleri ve statik yöntemleri arasında fark hakkında şöyle demektedir:

Statik yöntem nesneleri Statik yöntem nesneleri, işlev nesnelerinin yukarıda açıklanan yöntem nesnelerine dönüşümünü engellemenin bir yolunu sağlar. Statik yöntem nesnesi, genellikle kullanıcı tanımlı bir yöntem nesnesi olan diğer herhangi bir nesnenin etrafındaki bir sarıcıdır. Bir statik yöntem nesnesi bir sınıftan veya sınıf örneğinden alındığında, gerçekte döndürülen nesne, başka bir dönüştürmeye tabi olmayan sarılmış nesnedir. Statik yöntem nesneleri, kendilerine sarılmazlar, ancak sardıkları nesneler genellikle. Statik yöntem nesneleri, yerleşik staticmethod () yapıcısı tarafından oluşturulur.

Sınıf yöntemi nesneleri Bir sınıf yöntemi nesnesi, statik bir yöntem nesnesi gibi, başka bir nesnenin etrafındaki, bu nesnenin sınıflardan ve sınıf örneklerinden alınma şeklini değiştiren bir sarıcıdır. Sınıf yöntemi nesnelerinin bu tür bir alım üzerindeki davranışı yukarıda “Kullanıcı tanımlı yöntemler” altında açıklanmaktadır. Sınıf yöntemi nesneleri, yerleşik classmethod () yapıcısı tarafından oluşturulur.

İlgili sorular


4
@LightnessRacesinOrbit: Statik yöntemlerin python'da özellikle sık kullanıldığını sanmıyorum. Sistemimi rastgele bir örnek olarak kullanmak, kurduğum tüm paketleri araştırırken, tüm yöntemlerin yalnızca% 1'i statik yöntemlerdir (açıkçası beklediğimden daha fazlaydı).
Bryan Oakley

1
"Statik yöntemler" genellikle bir kod kokusudur ve örneğin Gogole Python stil rehberi tarafından önerilmez.
9000,

3
Bence, sınıflandırmaların bir miktar fayda sağladığı alt sınıflara dikkat çekerse, cevap daha iyi olur.
Winston Ewert,

1
@ user2357112: Ben sadece tüm örneklerini "^ def("saydım, sonra tüm örneklerini saydım @staticmethod. Çok bilimsel değil, ama muhtemelen basketbol sahası içindeydi.
Bryan Oakley

2
@ Kaşyap: TL; DR ilk paragrafa uygulanır. Ben üstte alttan daha iyi çalıştığını düşünüyorum.
Bryan Oakley

8

Python'da “sınıf yöntemleri” ve “örnek yöntemleri” nedir?

  • Bir "örnek yöntemi", hangi değerin geri döndürüleceğini (veya hangi yan etkinin yapılacağını) bulmak için bu örnekte yer alan bilgileri kullanır. Bunlar çok yaygın.

  • Bir "sınıf metodu" sınıfla ilgili bilgileri (ve o sınıfın bir örneğini değil) ne yaptığını etkilemek için kullanır (genellikle alternatif kurucular olarak yeni örnekler oluşturmak için kullanılır ve bu nedenle inanılmaz derecede yaygın değildir).

  • Bir "statik yöntem", ne yaptığını hesaplamak için sınıf veya örnek hakkında herhangi bir bilgi kullanmaz. Genellikle kolaylık sağlamak için sadece sınıfta. (Bu nedenle, bunlar da pek yaygın değildir.)

X'in bir İşlevi

Matematik sınıfını hatırlayın, "y, x'in bir işlevidir f(x)?" Bunu kodda uygulayalım:

y = function(x)

Yukarıdakilerin ima ettiği, xdeğişebileceğinden beri değiştiğinde ydeğişebileceğidir x. Biz "demek, bu kastedilen budur ybir fonksiyonudur x"

Ne olacak yne olmak zolduğunu 1? 2? 'FooBarBaz'?

ybir fonksiyonu değildir zbu yüzden, zher şey olabilir ve bizim varsayarak fonksiyonun sonucunu etkileyebilecek functionolan saf bir işlev. (Eğer zglobal bir değişken olarak erişirse , o zaman saf bir işlev değildir - işlevsel saflıkla kastedilen budur.)

Aşağıdaki açıklamaları okurken yukarıdakileri aklınızda bulundurun:

Örnek Yöntemleri

Bir örnek yöntemi fonksiyonu olan bir işlev ait bir örneği . İşlev, örneği dolaylı olarak bir argüman olarak kabul eder ve örnek, işlev tarafından çıktıyı belirlemek için işlev tarafından kullanılır.

Bir örnek yöntemi için yerleşik bir örnek str.lower:

>>> 'ABC'.lower()
'abc'

str.lower dize örneğine çağrılır ve hangi yeni dizenin döndürüleceğini bulmak için bu örnekte yer alan bilgileri kullanır.

Sınıf Yöntemleri:

Unutma, Python'da her şey bir nesnedir. Bu, sınıfın bir nesne olduğu ve bir işleve argüman olarak geçirilebileceği anlamına gelir.

A sınıfı bir yöntem bir fonksiyonu olan bir fonksiyondur ve sınıf . Sınıfı bir argüman olarak kabul eder.

Yerleşik bir örnek dict.fromkeys:

>>> dict.fromkeys('ABC')
{'C': None, 'B': None, 'A': None}

İşlev kendi sınıfını örtük olarak bilir, işlev, çıktısını etkilemek için sınıfı kullanır ve yinelenebilirden bu sınıftan yeni bir tane oluşturur. Bir OrderedDict, aynı yöntemi kullanırken bunu göstermektedir:

>>> from collections import OrderedDict
>>> OrderedDict.fromkeys('ABC')
OrderedDict([('A', None), ('B', None), ('C', None)])

Sınıf yöntemi, ne tür bir sınıf döndürüleceğini etkilemek için sınıfla ilgili bilgileri (ve o sınıfın bir örneğini değil) kullanır.

Statik Yöntemler

"Sınıfını bilmeyen" bir yöntemden bahsediyorsunuz - bu Python'da statik bir yöntemdir. Sadece sınıf nesnesine kolaylık sağlamak için eklenmiştir. İsteğe bağlı olarak başka bir modülde ayrı bir işlev olabilir, ancak çağrı imzası aynı olacaktır.

Statik yöntem, ne sınıf ne de nesnenin bir fonksiyonudur.

Bir statik yöntemin yerleşik bir örneği Python 3'ten str.maketrans'dır.

>>> str.maketrans('abc', 'bca')
{97: 98, 98: 99, 99: 97}

Birkaç argüman verildiğinde, sınıfının bir fonksiyonu olmayan bir sözlük yapar.

Kullanışlı çünkü strher zaman global isim alanında mevcuttur, böylece çevirme işleviyle kolayca kullanabilirsiniz:

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
'bcrbabdbcrb'

Python 2'de, stringmodülden erişmek zorundasınız :

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'str' has no attribute 'maketrans'
>>> import string
>>> 'abracadabra'.translate(string.maketrans('abc', 'bca'))
'bcrbabdbcrb'

Örnek

class AClass(object):
    """In Python, a class may have several types of methods: 
    instance methods, class methods, and static methods
    """

    def an_instance_method(self, x, y, z=None):
        """this is a function of the instance of the object
        self is the object's instance
        """
        return self.a_class_method(x, y)

    @classmethod
    def a_class_method(cls, x, y, z=None):
        """this is a function of the class of the object
        cls is the object's class
        """
        return cls.a_static_method(x, y, z=z)

    @staticmethod
    def a_static_method(x, y, z=None):
        """this is neither a function of the instance or class to 
        which it is attached
        """
        return x, y, z

Başlatalım:

>>> instance = AClass()

Şimdi örnek tüm yöntemleri çağırabilir:

>>> instance.an_instance_method('x', 'y')
('x', 'y', None)
>>> instance.a_static_method('x', 'y')
('x', 'y', None)
>>> instance.a_class_method('x', 'y')
('x', 'y', None)

Ancak, sınıfın diğerlerini çağırması beklense de, genellikle örnek yöntemi çağırmak için tasarlanmamıştır:

>>> AClass.a_class_method('x', 'y')
('x', 'y', None)
>>> AClass.a_static_method('x', 'y')
('x', 'y', None)
>>> AClass.an_instance_method('x', 'y')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: an_instance_method() missing 1 required positional argument: 'y'

Örnek yöntemi çağırmak için örneği açıkça iletmeniz gerekir:

>>> AClass.an_instance_method(instance, 'x', 'y')
('x', 'y', None)

"Bu Python'da statik bir yöntemdir. Yalnızca sınıf nesnesine kolaylık sağlamak için eklenmiştir. İsteğe bağlı olarak başka bir modülde ayrı bir işlev olabilir, ancak çağrı imzası aynı olacaktır." Uygun olandan daha kafa karıştırıcı görünüyor. Bedeni o sınıfa dair bir düşünceye sahip değilse, neden bir sınıfa bir fonksiyon takıyorsunuz?
Monica

@LightnessRacesinOrbit Her noktaya odaklandım
Aaron Hall

Şahsen, her zaman ona baktığım yöntem, bir örnek yönteminin belirli bir örnek üzerinde bir işlem olması, bir sınıf yönteminin bir tür kurucu (kolaylık sağlamak için, hiçbir şey gibi bir şey MyClass(1,2,3)değil MyClass.get_special(1,2,3)) ve statik bir yöntem olmasıdır. Zaten tek başına durabilecek normal bir işlev olmak.
Zizouz212

Evet, sınıf metotları tipik olarak alternatif yapıcılar için kullanılır (yukarıdaki anahtar örneğime bakın, ayrıca pandas.DataFrame kaynak koduna bakın), ama bu tanımlayıcı bir özellik değil. Bazen sadece sınıf düzeyinde depolanan verilere, bir örneğe erişmeden bir yöntemden erişmem gerekiyor. Type (self) (ya da daha kötüsü, self .__ class__) türünü çağırıyorsanız ve doğrudan kendini bir örnek yönteminde kullanmıyorsanız, bunun bir sınıf metodu olduğunu düşünmeniz gerektiğini gösteren iyi bir işaret. Sınıf metotları örnek gerektirmediğinden, onları en içte geçirmelerini kolaylaştırır.
Aaron Hall

4

C / C ++ / etc içerisinde "statik yöntem" teriminin kullanımı, hem Python "statik" hem de Python "sınıf" yöntemlerine uygulanır, çünkü bu yöntemlerin her ikisi de örneğe referans vermez. C / C ++ / etc'de, yöntemler normalde sınıfın tüm eşgörünüm üyelerine / yöntemlerine dolaysız erişime sahiptir, bu nedenle bu ayrım yalnızca Python / Ruby / etc gibi dillerde bulunur.


C / C ++ 'daki statik bir yöntemin sınıf nesnesine bir başvurusu var mı? Ya da sadece sınıfın "üyeleri"? Sınıfın yeni üyelerini yaratabilirler mi? :)
Aaron Hall

3
@AaronHall C / C ++ 'da class nesnesi diye bir şey yoktur ve statik yöntemleri çağırmak için bir referansa ihtiyacınız yoktur. Sadece Class::staticMethod()yazıyorsunuz ve hepsi bu ( staticMethod()özel veya bir şey olduğu için onu çağırmanız yasaklanmadığı sürece ).
Ixrec
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.