Başlayanlar üçün @classmethod və @ staticmethodun mənası?

Kimsə @classmethod@staticmethod @classmethod mənasını mənə izah edə bilərmi? Farkı və mənasını bilməliyəm.

Mən başa düşdüyüm kimi, @classmethod deyir ki, bu alt siniflərə və ya ... bir şeyə miras alınması lazım olan bir üsuldur. Ancaq bunun nə mənası var? Niyə yalnız @staticmethod ya da @ @staticmethod və ya hər hansı bir @staticmethod əlavə etmədən bir sinfi metodu tanımlamırsınız?

tl; Dr: Onları necə istifadə etməliyəm, niyə istifadə etməliyəm və necə istifadə etməliyəm?

C ++ ilə kifayət qədər inkişaf etdim, buna görə daha inkişaf etmiş proqramlaşdırma anlayışları problem olmur. Mümkünse mənə uyğun C ++ nümunəsini verməkdən çəkin.

1326
29 авг. avqustun 29-da user1632861- ə təyin olundu 2012-08-29 16:37 '12 at 4:37 pm 2012-08-29 16:37
@ 11 cavab

classmethodstaticmethod çox oxşar olsa da, hər iki obyekt üçün istifadədə bir az fərq var: classmethod sinif obyektinə ilk parametrə istinad etməlidir, classmethod isə heç bir parametrə malik ola bilməz.

bir nümunə

 class Date(object): def __init__(self, day=0, month=0, year=0): self.day = day self.month = month self.year = year @classmethod def from_string(cls, date_as_string): day, month, year = map(int, date_as_string.split('-')) date1 = cls(day, month, year) return date1 @staticmethod def is_date_valid(date_as_string): day, month, year = map(int, date_as_string.split('-')) return day <= 31 and month <= 12 and year <= 3999 date2 = Date.from_string('11-09-2012') is_date = Date.is_date_valid('11-09-2012') 

izahat

Məsələn, tarixi məlumatlarla əlaqəli bir sinif nümunəsi (məsələn, şablonumuz olacaq) deyək:

 class Date(object): def __init__(self, day=0, month=0, year=0): self.day = day self.month = month self.year = year 

Bu sinif müəyyən tarixləri (saat dilimi haqqında məlumat vermədən və bütün tarixlərin UTC-də olmadığı) barədə məlumatları saxlamaq üçün açıq-aydın istifadə edilə bilər.

Burada __init__ , Python sinifinin tipik bir nümunə başlanğıcına __init__ , yeni __init__ istinad edən ilk seçilmiş arqument ( self ) olan tipik bir instancemethod üsulu kimi arqumentlər qəbul edir.

Sinif metodu

classmethod istifadə edərək həyata keçirilə bilən bəzi vəzifələr var.

DD-mm-yyyy formatında bir simli kodlanmış bir xarici mənbədən tarixi məlumatı olan Date sinifinin bir çox nümunəsini yaratmaq istəyirik. Bunu layihəmizin mənbə kodunda fərqli yerlərdə etmək məcburiyyətindəyik.

Beləliklə, burada nə etməliyik?

  1. Gün, ay və il üçün üç tamsaylı dəyişən və ya bu dəyişəndən ibarət 3 elementli tuple olmaq üçün simli sökün.
  2. Başlanğıc çağırmaq üçün bu dəyərləri keçirərək Date yaratın.

Bu kimi görünür:

 day, month, year = map(int, string_date.split('-')) date1 = Date(day, month, year) 

Bunun üçün C ++ belə bir funksiyanı çox yüklə həyata keçirə bilər, amma Python bu yükə malik deyil. Bunun əvəzinə classmethod istifadə edə classmethod . Başqa bir "konstruktor" yaradın.

  @classmethod def from_string(cls, date_as_string): day, month, year = map(int, date_as_string.split('-')) date1 = cls(day, month, year) return date1 date2 = Date.from_string('11-09-2012') 

Yuxarıda göstərilən tətbiqə daha çox nəzər salaq və burada hansı üstünlükləri nəzərdən keçirək:

  1. Tarixi lentlərin bir yerdə ayrılmasını həyata keçirmişik və indi yenidən istifadə oluna bilərik.
  2. Encapsulation burada yaxşı işləyir (əgər başqa bir yerdə bir funksiya kimi birləşdirən simli tətbiq edə bilərəmsə, bu həll OOP paradiqmasına daha yaxşı uyğun gəlir).
  3. cls sinfi bir nümunəsi deyil, sinfi özündə ehtiva edən bir obyektdir. Bu, olduqca gözəldir, çünki Date sinifini devralırsak, bütün uşaqlar da from_string bir parametrdən istifadə edəcəklər.

Statik metod

Necə staticmethod haqqında? Bu sinif metoduna çox oxşardır, lakin tələb olunan parametrləri qəbul etmir (məsələn, sinfi metodu və ya nümunə metodu).

Növbəti istifadəyə baxaq.

Biz yoxlamaq istəyirik bir tarix simli var. Bu tapşırıq da məntiqi olaraq istifadə etdiyimiz Date sinifinə aiddir, lakin onun yaradılması tələb olunmur.

Burada staticmethod faydalı ola bilər. Aşağıdakı kod parçasına baxaq:

  @staticmethod def is_date_valid(date_as_string): day, month, year = map(int, date_as_string.split('-')) return day <= 31 and month <= 12 and year <= 3999 # usage: is_date = Date.is_date_valid('11-09-2012') 

Beləliklə, staticmethod istifadə staticmethod , bir sinfi meydana gətirdiyimizə heç bir staticmethod yoxdur: əsasən sintaktik cəhətdən oxşar bir üsul adlanır, lakin obyektin və onun daxili elementlərinin (sahələr və digər üsullar) sinif üsulu isə.

2245
29 авг. Rostislav Dzinko'nun cavabı 29 Avqust . 2012-08-29 17:03 '12 at 17:03 2012-08-29 17:03

Rostislav Dzinkonun cavabı çox uyğun gəlir. Əlavə bir konstruktor @classmethod , @staticmethod @classmethod üstündə @staticmethod başqa bir səbəbini @classmethod @staticmethod .

Yuxarıdakı nümunədə, Rostislav qəbuledilməz digər parametrlərdən Date obyektlərini yaratmaq üçün from_string olaraq @classmethod from_string istifadə @classmethod . Aşağıdakı @staticmethod göstərildiyi kimi, @staticmethod istifadə edilə bilər:

 class DateTime(Date): def display(self): return "{0}-{1}-{2} - 00:00:00PM".format(self.month, self.day, self.year) datetime1 = DateTime(10, 10, 1990) datetime2 = DateTime.millenium(10, 10) isinstance(datetime1, DateTime) # True isinstance(datetime2, DateTime) # False datetime1.display() # returns "10-10-1990 - 00:00:00PM" datetime2.display() # returns "10-10-2000" because it not a DateTime object but a Date object. Check the implementation of the millenium method on the Date class 

datetime2 nümunəsi deyil? WTF? Bəli, istifadə edilən dekoratorun @staticmethod .

border=0

Çox hallarda bu arzuolunmazdır. Əgər siz onu adlandırdığınız sinfi bilən Factory metodunu istifadə etmək istəyirsinizsə, @classmethod sizə lazım @classmethod .

Date.millenium kimi yenidən yazma (yuxarıda göstərilən kodun yalnız bir hissəsini dəyişən)

 datetime1 = DateTime(10, 10, 1990) datetime2 = DateTime.millenium(10, 10) isinstance(datetime1, DateTime) # True isinstance(datetime2, DateTime) # True datetime1.display() # "10-10-1990 - 00:00:00PM" datetime2.display() # "10-10-2000 - 00:00:00PM" 

Bunun səbəbi, bildiyiniz kimi, @classmethod istifadə @classmethod

742
30 янв. Yaw Boakye tərəfindən 30 Yanvarda cavab verildi 2013-01-30 16:35 '13 'da 16:35' da 2013-01-30 16:35 'da

@classmethod deməkdir: bu metod çağırıldıqda, sinfi bu sinifin bir nümunəsi əvəzinə ilk arqument kimi qəbul edirik (adətən metodlarla birlikdə olduğumuz kimi). Bu, özünəməxsus bir nümunə deyil, bu metod daxilində sinfi və xüsusiyyətlərini istifadə edə bilərsiniz.

@staticmethod deməkdir: bu üsul çağrıldığı zaman, biz bunu sinfi bir nümunə vermirik (adətən üsullarla aparılır). Bu, bir sinif içərisində bir funksiya qoymaq deməkdir, ancaq bu sinifin bir nümunəsinə daxil ola bilməzsiniz (bu metodunuz bir nümunəni istifadə etmədikdə faydalıdır).

218
29 авг. Cavab Simeon Visser 29 avqustda verilir. 2012-08-29 16:40 '12 at 4:40 pm 2012-08-29 16:40

Hər birini istifadə edərkən

@staticmethod funksiyası bir sinifdə müəyyən edilmiş bir funksiyadan daha çox şeydir. Sınıfın bir örneğini yaratmadan çağırılabilir. Onun təsviri miras yoluyla dəyişilməzdir.

  • Python, bir obyekt üçün bir bağlı metodu dərhal etməməlidir.
  • Bu kodun okunabilirliğini asanlaşdırır: @staticmethod'u görərək, metodun obyektin özündən asılı olmadığını bilirik;

@classmethod funksiyası bir sinifin dərhal edilməməsi @classmethod ola bilər, ancaq onun təsviri sub subclassı izləyir və miras vasitəsilə ana sinfi deyil, alt sinif tərəfindən yenidən təyin edilə bilər. Çünki @classmethod funksiyasına dair ilk arqument həmişə cls (class) @classmethod cls (class) .

  • Məsələn, bir sıra preprocessing istifadə edən bir sinif üçün bir nümunə yaratmaq üçün istifadə olunan zavod üsulları .
  • Statik metodları adlandırdığınız statik metodlar : statik metodları bir neçə statik metodlarla sındırarsanız, sinif adını hard-code etməlisiniz, lakin sinif metodlarından istifadə etməliyəm

Burada bu mövzuda yaxşı bir əlaqə var.

58
14 апр. Cavab zangw 14 apr verilir . 2014-04-14 10:12 '14 at 10:12 2014-04-14 10:12

@classmethod alt sinifinə əsaslanan bir üsulun davranışını dəyişdirmək @classmethod istifadə edə bilərsiniz. Sinif metodunda çağırış sinifinə istinad etdiyimizi unutmayın.

Statik istifadə edərkən, davranışın alt siniflər arasında dəyişməz qalmasını istəyir.

Məsələn:

 class Hero: @staticmethod def say_hello(): print("Helllo...") @classmethod def say_class_hello(cls): if(cls.__name__=="HeroSon"): print("Hi Kido") elif(cls.__name__=="HeroDaughter"): print("Hi Princess") class HeroSon(Hero): def say_son_hello(self): print("test hello") class HeroDaughter(Hero): def say_daughter_hello(self): print("test hello daughter") testson = HeroSon() testson.say_class_hello() #Output: "Hi Kido" testson.say_hello() #Outputs: "Helllo..." testdaughter = HeroDaughter() testdaughter.say_class_hello() #Outputs: "Hi Princess" testdaughter.say_hello() #Outputs: "Helllo..." 
32
21 авг. Krishnendu Kunti tərəfindən verilmiş cavab 21 Avqust. 2015-08-21 10:18 '15 saat 10:18 'da

Kiçik tərtib

@ staticmethod Bir sinif daxilində bir metod yazmaq üçün istifadə edilən obyektə istinad etmədən yazma metodu. Buna görə də, özünü və ya özünü göstərmək kimi bir örtük arqument keçirməyə ehtiyac yoxdur. Bu, sinfi xaricində yazılmış yazı ilə eyni şəkildə yazılmışdır, ancaq piton üçün lazımsız deyil, çünki bir sinif daxilində bir metodu əhatə etməlisiniz, çünki bu üsul bu sinifin bir hissəsi olmalıdır, çünki bu halda @ stati metod üsulu rahatdır.

@classmethod Fabrika metodunu yazmaq istədiyiniz zaman vacibdir və bu xüsusi xüsusiyyət sinifə əlavə edilə bilər. Bu xüsusiyyət miras alınmış sinifdə ləğv edilə bilər.

Bu iki üsulun müqayisəsi daha aşağı ola bilər.

2019

19 июля '15 в 19:43 2015-07-19 19:43 Cavab Sİslam tərəfindən 19 iyul 'da 19:43' da verilir

@classmethod@staticmethod ?

  • Bir üsul, öznitelik olaraq mövcud olan bir obyekt ad boşluğunda bir funksiyadır.
  • Normal (yəni nümunə) metodu bir örnək olur (biz adətən self özümüz deyirik) örtülü ilk arqument kimi.
  • Bir sinif metodu, bir örtük ilk arqument kimi bir sinif alır (biz adətən bunu cls deyirik).
  • Statik metod örtük ilk dəlil (məsələn, müntəzəm funksiya) qəbul etmir.

Onları necə istifadə edəcəyəm, niyə istifadə etməliyəm və necə istifadə etməliyəm?

Bir dekorativə ehtiyacınız yoxdur. Amma funksiya argümanlarının sayını minimuma endirmə prinsipinə əsasən (bax "Təmiz Coder") onlar üçün faydalıdır.

 class Example(object): def regular_instance_method(self): """A function of an instance has access to every attribute of that instance, including its class (and its attributes.) Not accepting at least one argument is a TypeError. Not understanding the semantics of that argument is a user error. """ return some_function_f(self) @classmethod def a_class_method(cls): """A function of a class has access to every attribute of the class. Not accepting at least one argument is a TypeError. Not understanding the semantics of that argument is a user error. """ return some_function_g(cls) @staticmethod def a_static_method(): """A static method has no information about instances or classes unless explicitly given. It just lives in the class (and thus its instances') namespace. """ return some_function_h() 

Hər iki nümunə üsul və sinif metodları üçün, ən azı bir arqument götürmədən, TypeError, lakin bu sübutun semantikasını anlamadan, bu bir istifadəçi səhvidir.

( some_function müəyyən some_function , məsələn:

 some_function_h = some_function_g = some_function_f = lambda x=None: x 

və işləyəcək.)

Nümunələr və siniflərdə nöqtəli axtarış:

Bu qaydada dəqiq bir instansiya axtarışı həyata keçirilir - biz aradık:

  1. sinif ad boşluğunda bir məlumat təsvirçisi (məsələn, bir əmlak)
  2. məlumat nümunəsi __dict__
  3. sinif ad boşluğunda (üsullar) məlumat olmadan identifikator.

Xırdalanan nümunə axtarışın aşağıdakı kimi vurğulandığını unutmayın:

 instance = Example() instance.regular_instance_method 

və üsulları atributlar deyilir:

 instance.regular_instance_method() 

nümunə üsulları

Dəlil, self , nöqtəli bir axtarış vasitəsi ilə örtülü şəkildə göstərilmişdir.

Dərs nümunələrindən nümunə üsullarına daxil olmalısınız.

 >>> instance = Example() >>> instance.regular_instance_method() <__main__.Example object at 0x00000000399524E0> 

sinif üsulları

cls arqumenti bir nöqtə axtarışı ilə dolğun olaraq müəyyən edilir.

Bu metodu bir nümunə və ya sinif (və ya alt siniflər) vasitəsilə əldə edə bilərsiniz.

 >>> instance.a_class_method() <class '__main__.Example'> >>> Example.a_class_method() <class '__main__.Example'> 

statik metodlar

Heç bir dəlil yoxdur. Bu metod, axtarış edilə biləcəyi istisna olmaqla, bir modul ad boşluğunda müəyyən edilmiş (məsələn) hər hansı bir funksiya kimi işləyir.

 >>> print(instance.a_static_method()) None 

Yenə də, onlardan istifadə etməliyəm, niyə istifadə etməliyəm?

Bunların hər biri tədricən metod üsulu ilə ötürülən məlumatları tədricən daha da məhdudlaşdırır.

Məlumat ehtiyacınız olmadıqda onları istifadə edin.

Bu, funksiyalarınızın və metodların tərifini asanlaşdırır və aradan qaldırır.

Nə danışmaq daha asandır?

 def function(x, y, z): ... 

və ya

 def function(y, z): ... 

və ya

 def function(z): ... 

Daha az dəlilləri olan funksiyaları ilə müzakirə etmək asandır. Onlar da aradan qaldırılması üçün daha asandır.

Onlar nümunə, sinif və statik metodlardan daha üstündür. Bir nümunə olduğumuz zaman xatırlayırıq ki, öz siniflərimiz var, yenə danışmaq daha asan nədir?

 def an_instance_method(self, arg, kwarg=None): cls = type(self) # Also has the class of instance! ... @classmethod def a_class_method(cls, arg, kwarg=None): ... @staticmethod def a_static_method(arg, kwarg=None): ... 

Gömülmüş nümunələr

Burada mənim ən çox sevdiyim nümunələrdən bir neçəsi var:

Statik metod str.maketrans string modulda bir funksiyadır, lakin str ad sahəsindən istifadə etmək üçün daha əlverişlidir.

 >>> 'abc'.translate(str.maketrans({'a': 'b'})) 'bbc' 

dict.fromkeys metodu əsas təkrarlama ilə yaradılmış yeni bir lüğət qaytarır:

 >>> dict.fromkeys('abc') {'a': None, 'c': None, 'b': None} 

Bir alt sinifdə gördük ki, sinif metodu kimi məlumatlar çox faydalıdır:

 >>> class MyDict(dict): pass >>> type(MyDict.fromkeys('abc')) <class '__main__.MyDict'> 

Mənim məsləhətim - Nəticə

Sinif və ya instansiya argumentlərinə ehtiyac olmadıqda statik metodları istifadə edin, lakin funksiya bir obyektin istifadəsi ilə əlaqələndirilir və funksiya obyektin ad boşluğunda rahatdır.

Məsələn məlumatlara ehtiyacınız olmadığı halda sinif metodlarını istifadə edin, lakin sinif məlumatlarına ehtiyacınız var, bəlkə də başqa bir sinif və ya statik metodlar üçün, ya da bəlkə də bir konstruktor olaraq. (Alt siniflərin burada istifadə oluna biləcəyi üçün sinifləri hardcode etməyəcəksiniz.)

27
24 окт. Cavab 24 oktyabrda Aaron Hall tərəfindən verilir . 2017-10-24 19:09 '17 saat 07:09 'da 2017-10-24 19:09

Mən bu saytda yeniyim, yuxarıda göstərilən cavabları oxuyuram və istədiyim məlumatları aldım. Ancaq qaldırmaq haqqım yoxdur. Beləliklə, mən StackOverflow ilə başa düşdüyüm kimi cavab ilə başlamaq istəyirəm.

  • @staticmethod ilk parametri kimi özünü yaxud @staticmethod ehtiyac @staticmethod
  • @staticmethod@classmethod sertifikatlaşdırılmış funksiya bir nümunə və ya sinif dəyişən adlanır
  • @staticmethod bəzədilmiş funksiyası bir subclassın mirasçılığı @ statiomethodun @staticmethod tərəfindən bükülmüş olan əsas sinif funksiyasının üzərində yaza bilməyəcəyi bir növ "dəyişməz əmlak" a təsir edir.
  • @classmethod , cls tələb edir (sinif adı, siz dəyişən adını dəyişə bilərsiniz, lakin bu təklif edilmir) funksiyanın ilk parametri kimi
  • @classmethod həmişə bir alt sinif yolunda istifadə olunur, bir alt sinfi devralma, bir əsas sinif funksiyasının təsirini dəyişə bilər, yəni. @classmethod baza sinifinin @classmethod funksiyası müxtəlif subclasslar tərəfindən yazıla bilər.
1
23 июля '17 в 14:38 2017-07-23 14:38 Cavab Yi Chen tərəfindən 23 İyul tarixində '17 də 14:38 2017-07-23 14:38 'də verilir

Bir sözlə, @classmehtod adi üsulu zavod üsuluna çevirir.

Bir nümunə götürək:

 class PythonBook: def __init__(self, name, author): self.name = name self.author = author def __repr__(self): return f'Book: {self.name}, Author: {self.author}' 

@ Klass üsulu olmadan, yaradılan nümunələri bir-bir ilə işləməlisən və onlar bükülmüşdür.

 book1 = PythonBook('Learning Python', 'Mark Lutz') In [20]: book1 Out[20]: Book: Learning Python, Author: Mark Lutz book2 = PythonBook('Python Think', 'Allen B Dowey') In [22]: book2 Out[22]: Book: Python Think, Author: Allen B Dowey 

Məsələn, @classmethod istifadə edin

 class PythonBook: def __init__(self, name, author): self.name = name self.author = author def __repr__(self): return f'Book: {self.name}, Author: {self.author}' @classmethod def book1(cls): return cls('Learning Python', 'Mark Lutz') @classmethod def book2(cls): return cls('Python Think', 'Allen B Dowey') 

Bunu cəhd edin:

 In [31]: PythonBook.book1() Out[31]: Book: Learning Python, Author: Mark Lutz In [32]: PythonBook.book2() Out[32]: Book: Python Think, Author: Allen B Dowey 

Baxın? Nümunələr sinif tərifində uğurla yaradılır və bir araya gəlir.

Nəhayət, dekorator @classmethod ənənəvi üsulu zavod üsuluna çevirir. Sınıf metodlarını istifadə etmək mümkün qədər çox alternativ konstruktor əlavə etməyə imkan verir.

0
12 дек. Cavab JawSaw tərəfindən verilir 12 dekabr. 2017-12-12 12:41 '17 də 12:41 PM 2017-12-12 12:41

Bu barədə düşünmək üçün bir az daha fərqli bir yol, kimsə üçün faydalı ola bilər ... Sınıf üsulu, bu metodun müxtəlif uşaq siniflərindən istifadə edildikdə necə davranılacağını müəyyən etmək üçün istifadə olunur. Eyni şeyi geri qaytarmaq istəyiriksə, statik bir metoddan istifadə edir, nə olursa olsun biz çağırırıq.

0
25 янв. Cavab 25 yanvarda boson verilir 2017-01-25 01:59 '17 də 1:59 2017-01-25 01:59

Sinif metodu sinifin vəziyyətini dəyişdirə bilər, sinfi ilə əlaqələndirir və parametr kimi cls parametrini ehtiva edir.

Statik metod bir sinifin vəziyyətini dəyişdirə bilməz, sinfi ilə əlaqələndirilir və sinif və ya nümunəni bilmir.

 class empDetails: def __init__(self,name,sal): self.name=name self.sal=sal @classmethod def increment(cls,name,none): return cls('yarramsetti',6000 + 500) @staticmethod def salChecking(sal): return sal > 6000 emp1=empDetails('durga prasad',6000) emp2=empDetails.increment('yarramsetti',100) # output is 'durga prasad' print emp1.name # output put is 6000 print emp1.sal # output is 6500,because it change the sal variable print emp2.sal # output is 'yarramsetti' it change the state of name variable print emp2.name # output is True, because ,it change the state of sal variable print empDetails.salChecking(6500) 
-2
02 сент. cavab verdi y durga prasad 02 Sentyabr 2017-09-02 17:34 '17 də 5:34 pm 2017-09-02 17:34