Bir fonksiyonu süslenmiş arasındaki fark nedir @staticmethod
ve bir dekore @classmethod
?
Bir fonksiyonu süslenmiş arasındaki fark nedir @staticmethod
ve bir dekore @classmethod
?
Yanıtlar:
Çağrı imzaları fark farkını: Belki örnek kod biraz yardımcı olacaktır foo
, class_foo
ve static_foo
:
class A(object):
def foo(self, x):
print "executing foo(%s, %s)" % (self, x)
@classmethod
def class_foo(cls, x):
print "executing class_foo(%s, %s)" % (cls, x)
@staticmethod
def static_foo(x):
print "executing static_foo(%s)" % x
a = A()
Aşağıda, bir nesne örneğinin bir yöntemi çağırmasının olağan yolu verilmiştir. Nesne örneği, a
dolaylı olarak ilk argüman olarak geçirilir.
a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)
Classmethods ile , bir nesne, örneğin sınıf dolaylı yerine ilk bağımsız değişken olarak geçirilir self
.
a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)
class_foo
Sınıfı kullanarak da arayabilirsiniz . Aslında, bir şeyi bir sınıf yöntemi olarak tanımlarsanız, bunun nedeni büyük olasılıkla onu bir sınıf örneğinden ziyade sınıftan çağırmak istemenizdir. A.foo(1)
bir TypeError oluşturur, ancak iyi A.class_foo(1)
çalışır:
A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)
İnsanların sınıf yöntemleri için buldukları bir kullanım, kalıtımsal alternatif kurucular yaratmaktır .
Statik yöntemlerle , ne self
(nesne örneği) ne de cls
(sınıf) ilk argüman olarak örtük olarak geçirilmez. Bunları bir örnek veya sınıftan çağırabilmeniz dışında düz işlevler gibi davranırlar:
a.static_foo(1)
# executing static_foo(1)
A.static_foo('hi')
# executing static_foo(hi)
Staticmethods, bir sınıfla sınıfla mantıksal bağlantısı olan işlevleri gruplandırmak için kullanılır.
foo
sadece bir işlevdir, ancak çağırdığınızda işlevi a.foo
almayacaksınız, işlevin a
ilk argümanı olarak bağlı nesne örneği ile işlevin "kısmen uygulanmış" sürümünü alırsınız . foo
2 bağımsız değişken, a.foo
yalnızca 1 bağımsız değişken bekler.
a
bağlı foo
. Aşağıdaki "bağlı" terimi ile kastedilen:
print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>
İle a.class_foo
, a
bağlı değil class_foo
, daha ziyade sınıf A
bağlı class_foo
.
print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>
Burada, bir statik yöntemle, bir yöntem olmasına rağmen, a.static_foo
yalnızca bağımsız bir işlev olmadan bağımsız bir 'ole işlevi döndürür. static_foo
1 bağımsız değişken ve
a.static_foo
1 bağımsız değişken de bekliyor.
print(a.static_foo)
# <function static_foo at 0xb7d479cc>
Ve elbette aynı şey static_foo
sınıfla aradığınızda da olur A
.
print(A.static_foo)
# <function static_foo at 0xb7d479cc>
@staticmethod
bulamamam da, alt sınıflar tarafından geçersiz kılınarak kodunuzu düzenlemenize yardımcı olabilir. Bu olmadan, modül ad alanında fonksiyonun değişkenleri olurdu.
@staticmethod
- ritmi kaldırmak için kullanabilirsiniz. Python'da bir programlama dili uyguluyorum - kütüphane tanımlı işlevler execute
, kullanıcı tanımlı işlevlerin örnek bağımsız değişkenler (işlev gövdesi) gerektirdiği statik bir yöntem kullanır . Bu dekoratör, PyCharm denetçisindeki "kullanılmayan parametre öz" uyarılarını ortadan kaldırır.
Bir durukyöntem Üzerinde denilen sınıf veya örneği hakkında hiçbir şey bilmeyen bir yöntemdir. Sadece geçirilen argümanları alır, üstü kapalı ilk argüman yoktur. Temelde Python'da işe yaramaz - statik yöntem yerine sadece bir modül işlevi kullanabilirsiniz.
Bir classmethod , diğer taraftan, birinci bağımsız değişken olarak, bu ilgili denilen sınıfı ya da üzerinde denilen örneğinin sınıfı geçirilen bir yöntemdir. Bu, yöntemin sınıf için bir fabrika olmasını istediğinizde yararlıdır: ilk argüman olarak çağrıldığı gerçek sınıfı aldığından, alt sınıflar dahil olsa bile her zaman doğru sınıfı başlatabilirsiniz. Örneğin dict.fromkeys()
, bir sınıf yönteminin , bir alt sınıfta çağrıldığında alt sınıfın bir örneğini nasıl verdiğini gözlemleyin :
>>> class DictSubclass(dict):
... def __repr__(self):
... return "DictSubclass"
...
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>>
Temel olarak @classmethod
, ilk argümanı çağrıldığı sınıf olan (sınıf örneği yerine), @staticmethod
herhangi bir örtülü argüman içermeyen bir yöntem yapar .
Resmi python belgeleri:
Sınıf yöntemi, tıpkı bir örnek yönteminin örneği alması gibi, sınıfı örtük ilk bağımsız değişken olarak alır. Bir sınıf yöntemi bildirmek için şu deyimi kullanın:
class C: @classmethod def f(cls, arg1, arg2, ...): ...
@classmethod
Form bir işlevdir dekoratör - fonksiyonu tanımların açıklamasına bakın Fonksiyon tanımları ayrıntılar için.Sınıfta (örneğin
C.f()
) veya bir örnekte (örneğin) çağrılabilirC().f()
. Örnek, sınıfı dışında yok sayılır. Türetilmiş bir sınıf için bir sınıf yöntemi çağrılırsa, türetilmiş sınıf nesnesi, zımni ilk bağımsız değişken olarak iletilir.Sınıf yöntemleri C ++ veya Java statik yöntemlerinden farklıdır. Bunları istiyorsanız,
staticmethod()
bu bölüme bakın.
Statik bir yöntem, örtük bir ilk argüman almaz. Statik bir yöntem bildirmek için şu deyimi kullanın:
class C: @staticmethod def f(arg1, arg2, ...): ...
@staticmethod
Form bir işlevdir dekoratör - fonksiyonu tanımların açıklamasına bakın Fonksiyon tanımları ayrıntılar için.Sınıfta (örneğin
C.f()
) veya bir örnekte (örneğin) çağrılabilirC().f()
. Örnek, sınıfı dışında yok sayılır.Python'daki statik yöntemler Java veya C ++ 'da bulunanlara benzer. Daha gelişmiş bir konsept
classmethod()
için bu bölüme bakın.
İşte bu soru hakkında kısa bir makale
@staticmethod işlevi, bir sınıf içinde tanımlanan bir işlevden başka bir şey değildir. İlk önce sınıfı somutlaştırmadan çağrılabilir. Tanımı kalıtım yoluyla değişmez.
@classmethod işlevi sınıfı somutlaştırmadan da çağrılabilir, ancak tanımı kalıtım yoluyla Üst sınıf değil Alt sınıftan sonra gelir. Çünkü @classmethod işlevi için ilk argüman her zaman cls (sınıf) olmalıdır.
@Staticmethod veya @classmethod kullanıp kullanmayacağınıza karar vermek için yönteminizin içine bakmanız gerekir. Yönteminiz sınıfınızdaki diğer değişkenlere / yöntemlere erişiyorsa @classmethod kullanın . Öte yandan, yönteminiz sınıfın başka bir yerine dokunmuyorsa, @staticmethod kullanın.
class Apple:
_counter = 0
@staticmethod
def about_apple():
print('Apple is good for you.')
# note you can still access other member of the class
# but you have to use the class instance
# which is not very nice, because you have repeat yourself
#
# For example:
# @staticmethod
# print('Number of apples have been juiced: %s' % Apple._counter)
#
# @classmethod
# print('Number of apples have been juiced: %s' % cls._counter)
#
# @classmethod is especially useful when you move your function to other class,
# you don't have to rename the class reference
@classmethod
def make_apple_juice(cls, number_of_apples):
print('Make juice:')
for i in range(number_of_apples):
cls._juice_this(i)
@classmethod
def _juice_this(cls, apple):
print('Juicing %d...' % apple)
cls._counter += 1
cls._counter
cls._counter
kod farklı bir sınıfa yerleştirilse veya sınıf adı değiştirilse bile yine de olur. sınıfa Apple._counter
özeldir Apple
; farklı bir sınıf için veya sınıf adı değiştirildiğinde, referans verilen sınıfı değiştirmeniz gerekir.
Python'da @staticmethod ve @classmethod arasındaki fark nedir?
Çeşitli yöntem türlerinin imzalarını gösteren ve her birini açıklamak için bir doktora sağlayan bu sahte kod gibi Python kodunu görmüş olabilirsiniz:
class Foo(object):
def a_normal_instance_method(self, arg_1, kwarg_2=None):
'''
Return a value that is a function of the instance with its
attributes, and other arguments such as arg_1 and kwarg2
'''
@staticmethod
def a_static_method(arg_0):
'''
Return a value that is a function of arg_0. It does not know the
instance or class it is called from.
'''
@classmethod
def a_class_method(cls, arg1):
'''
Return a value that is a function of the class and other arguments.
respects subclassing, it is called with the class it is called from.
'''
Önce açıklayacağım a_normal_instance_method
. Buna tam olarak " örnek yöntemi " denir " . Bir örnek yöntemi kullanıldığında, kısmi bir işlev olarak kullanılır (kaynak kodunda görüntülendiğinde tüm değerler için tanımlanmış toplam işlevin aksine), yani kullanıldığında, bağımsız değişkenlerin ilki öntanımlı nesne, verilen tüm özellikleri ile birlikte. Kendisine bağlı nesnenin örneğine sahiptir ve nesnenin bir örneğinden çağrılmalıdır. Genellikle, örneğin çeşitli özniteliklerine erişir.
Örneğin, bu bir dizenin örneğidir:
', '
join
Bu dizede, başka bir yinelenebilir öğeye katılmak için örnek yöntemini kullanırsak , yinelenebilir listenin bir işlevi olmasının yanı sıra, örneğin bir işlevi de oldukça açıktır ['a', 'b', 'c']
:
>>> ', '.join(['a', 'b', 'c'])
'a, b, c'
Örnek yöntemleri daha sonra kullanılmak üzere noktalı bir arama ile bağlanabilir.
Örneğin, bu str.join
yöntem ':'
örneğe bağlanır :
>>> join_with_colons = ':'.join
Ve daha sonra bunu ilk argümana zaten bağlı olan bir işlev olarak kullanabiliriz. Bu şekilde, örnek üzerinde kısmi bir işlev gibi çalışır:
>>> join_with_colons('abcde')
'a:b:c:d:e'
>>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF'])
'FF:FF:FF:FF:FF:FF'
Statik yöntem yok değil bir argüman olarak örneğini almak.
Bir modül seviyesi fonksiyonuna çok benzer.
Ancak, modül düzeyinde bir işlev modülde yaşamalı ve özel olarak kullanıldığı diğer yerlere aktarılmalıdır.
Ancak nesneye bağlıysa, içe aktarma ve miras yoluyla da nesneyi rahatlıkla izleyecektir.
Statik bir yöntem örneği str.maketrans
, string
Python 3'teki modülden taşınmıştır str.translate
. Aşağıda gösterildiği gibi, bir dizenin bir örneğinden kullanıldığında oldukça aptalca görünmektedir, ancak işlevi string
modülden içe aktarmak oldukça sakıncadır ve onu olduğu gibi sınıftan çağırabilmek güzeldir.str.maketrans
# demonstrate same function whether called from instance or not:
>>> ', '.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}
>>> str.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}
Python 2'de, giderek daha az kullanışlı dize modülünden bu işlevi içe aktarmanız gerekir:
>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'
Sınıf yöntemi, örtük bir ilk bağımsız değişken alması nedeniyle bir örnek yöntemine benzer, ancak örneği almak yerine sınıfı alır. Bunlar genellikle daha iyi semantik kullanım için alternatif kurucular olarak kullanılır ve kalıtımı destekler.
Yerleşik bir sınıf yönteminin en kanonik örneği dict.fromkeys
. Alternatif bir dict kurucu olarak kullanılır, (anahtarlarınızın ne olduğunu bildiğinizde ve onlar için varsayılan bir değer istediğinizde çok uygundur.)
>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}
Alt sınıfı dikte ettiğimizde, alt sınıfın bir örneğini oluşturan aynı yapıcıyı kullanabiliriz.
>>> class MyDict(dict): 'A dict subclass, use to demo classmethods'
>>> md = MyDict.fromkeys(['a', 'b', 'c'])
>>> md
{'a': None, 'c': None, 'b': None}
>>> type(md)
<class '__main__.MyDict'>
Bkz pandalar kaynak kodunu alternatif inşaatçı diğer benzer örnekler için ve ayrıca resmi Python belgelerine bakın classmethod
ve staticmethod
.
C ++ ve sonra Java ve sonra Python ile programlama dilini öğrenmeye başladım ve bu soru, her birinin basit kullanımını anlayana kadar beni de rahatsız etti.
Sınıf Metodu: Java ve C ++ 'dan farklı olarak Python'da yapıcı aşırı yüklemesi yoktur. Ve bunu başarmak için kullanabilirsiniz classmethod
. Aşağıdaki örnek bunu açıklayacaktır
Person
İki argüman alan first_name
ve last_name
örneğini yaratan bir sınıfımız olduğunu düşünelim Person
.
class Person(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
Eğer sadece bir, sadece tek bir ad kullanarak bir sınıf oluşturmak için gereken yere Şimdi, eğer gereksinim geliyor first_name
, sen olamaz Python böyle bir şey yapmak.
Bir nesne (örnek) oluşturmaya çalıştığınızda bu size bir hata verecektir.
class Person(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def __init__(self, first_name):
self.first_name = first_name
Ancak, @classmethod
aşağıda belirtilenleri kullanarak aynı şeyi başarabilirsiniz
class Person(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@classmethod
def get_person(cls, first_name):
return cls(first_name, "")
Statik Yöntem: Bu oldukça basittir, örneğe veya sınıfa bağlı değildir ve bunu sınıf adını kullanarak arayabilirsiniz.
Diyelim ki yukarıdaki örnekte first_name
20 karakteri geçmemesi gereken bir doğrulamaya ihtiyacınız var , bunu yapabilirsiniz.
@staticmethod
def validate_name(name):
return len(name) <= 20
ve sadece class name
Person.validate_name("Gaurang Shah")
def __init__(self, first_name, last_name="")
yerine bir veya iki argümanı kabul eden yapıcıya ulaşmanın daha pythonic yolu get_person
. Ayrıca sonuç bu durumda tamamen aynı olacaktır.
Bence daha iyi bir soru "@classmethod vs @staticmethod ne zaman kullanılır?"
@classmethod, sınıf tanımıyla ilişkili özel üyelere kolay erişim sağlar. bu, tek tektonlar veya oluşturulan nesnelerin örnek sayısını kontrol eden fabrika sınıfları yapmanın harika bir yoludur.
@staticmethod marjinal performans artışları sağlıyor, ancak sınıf içinde bağımsız bir işlev olarak elde edilemeyen bir sınıf içinde statik bir yöntemin verimli bir şekilde kullanılmasını henüz görmedim.
python 2.4'e @decorators eklendi. python <2.4 kullanıyorsanız classmethod () ve staticmethod () işlevini kullanabilirsiniz.
Örneğin, bir fabrika yöntemi (hangi argümana sahip olduğuna bağlı olarak sınıfın farklı bir uygulamasının bir örneğini döndüren bir işlev) oluşturmak istiyorsanız, şöyle bir şey yapabilirsiniz:
class Cluster(object):
def _is_cluster_for(cls, name):
"""
see if this class is the cluster with this name
this is a classmethod
"""
return cls.__name__ == name
_is_cluster_for = classmethod(_is_cluster_for)
#static method
def getCluster(name):
"""
static factory method, should be in Cluster class
returns a cluster object for the given name
"""
for cls in Cluster.__subclasses__():
if cls._is_cluster_for(name):
return cls()
getCluster = staticmethod(getCluster)
Ayrıca, bunun bir sınıf yöntemi ve statik yöntem kullanmak için iyi bir örnek olduğunu gözlemleyin, Statik yöntem açıkça sınıfa aittir, çünkü Küme sınıfını dahili olarak kullanır. Sınıf yöntemi yalnızca sınıf hakkında bilgiye ihtiyaç duyar ve nesnenin hiçbir örneğine sahip değildir.
_is_cluster_for
Yöntemi bir sınıf yöntemi haline getirmenin diğer bir yararı, bir alt sınıfın uygulamayı değiştirmeye karar verebilmesidir, belki de oldukça genel olduğundan ve birden fazla küme türünü işleyebildiğinden, sınıfın adını kontrol etmek yeterli olmaz.
Statik Yöntemler:
Statik Yöntemlerin Faydaları:
Her yöntemin özel olarak içe aktarılması gerekmediğinden modül düzeyinde işlevlere karşı içe aktarma daha uygun
@staticmethod
def some_static_method(*args, **kwds):
pass
Sınıf Yöntemleri:
Bunlar classmethod yerleşik işleviyle oluşturulur.
@classmethod
def some_class_method(cls, *args, **kwds):
pass
@staticmethod
yöntem tanımlayıcı olarak varsayılan işlevi devre dışı bırakır. classmethod, işlevinizi birinci bağımsız değişken olarak sahip olan sınıfa başvuru ileten çağrılabilir bir kapta sarar:
>>> class C(object):
... pass
...
>>> def f():
... pass
...
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>
Nitekim, classmethod
bir çalışma zamanı yükü vardır, ancak sahip olan sınıfa erişmeyi mümkün kılar. Alternatif olarak, bir metasınıf kullanmanızı ve bu metasınıfın sınıf yöntemlerini koymanızı öneririm:
>>> class CMeta(type):
... def foo(cls):
... print cls
...
>>> class C(object):
... __metaclass__ = CMeta
...
>>> C.foo()
<class '__main__.C'>
c = C(); c.foo()
AttributeError'ı kaldırır, yapmanız gerekir type(c).foo()
. Bu da bir özellik olarak düşünülebilir - neden düşünmek istediğinizi düşünemiyorum.
Python'da statik, sınıf veya soyut yöntemlerin nasıl kullanılacağına dair kesin kılavuz, bu konu için iyi bir bağlantıdır ve aşağıdaki gibi özetleyin.
@staticmethod
işlev, bir sınıf içinde tanımlanan bir işlevden başka bir şey değildir. İlk önce sınıfı somutlaştırmadan çağrılabilir. Tanımı kalıtım yoluyla değişmez.
@classmethod
işlevi sınıfı somutlaştırmadan da çağrılabilir, ancak tanımını kalıtım yoluyla üst sınıf değil Alt sınıf izler, alt sınıf tarafından geçersiz kılınabilir. Çünkü @classmethod
işlev için ilk argüman her zaman cls (sınıf) olmalıdır.
Sadece ilk argüman farklıdır :
Daha ayrıntılı olarak ...
Bir nesnenin yöntemi çağrıldığında, otomatik self
olarak ilk argümanı olarak ekstra bir argüman verilir . Yani, yöntem
def f(self, x, y)
2 argümanla çağrılmalıdır. self
otomatik olarak iletilir ve nesnenin kendisidir .
Yöntem süslendiğinde
@classmethod
def f(cls, x, y)
otomatik olarak sağlanan argüman değil self
, fakat sınıf self
.
Yöntem süslendiğinde
@staticmethod
def f(x, y)
yönteme hiçbir otomatik argüman verilmez . Sadece çağrıldığı parametreler verilir.
classmethod
çoğunlukla alternatif kurucular için kullanılır. staticmethod
nesnenin durumunu kullanmaz. Bir sınıfa harici bir işlev olabilir. Yalnızca benzer işlevlere sahip işlevleri gruplamak için sınıfın içine yerleştirilir (örneğin, Java'nın Math
sınıf statik yöntemleri gibi)class Point
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def frompolar(cls, radius, angle):
"""The `cls` argument is the `Point` class itself"""
return cls(radius * cos(angle), radius * sin(angle))
@staticmethod
def angle(x, y):
"""this could be outside the class, but we put it here
just because we think it is logically related to the class."""
return atan(y, x)
p1 = Point(3, 2)
p2 = Point.frompolar(3, pi/4)
angle = Point.angle(3, 2)
Önce @classmethod vs @staticmethod ile dekore edilmiş bir yöntem arasındaki benzerliği söyleyeyim.
Benzerlik: Her ikisi de sadece sınıf örneği yerine Sınıfın kendisinde çağrılabilir . Yani her ikisi de bir anlamda Class'ın yöntemleridir .
Fark: Bir sınıf yöntemi, sınıfın kendisini ilk argüman olarak alırken, bir statik yöntem bunu yapmaz.
Dolayısıyla statik bir yöntem, bir anlamda, Sınıfın kendisine bağlı değildir ve sadece ilgili bir işlevselliğe sahip olabileceği için orada asılı kalır.
>>> class Klaus:
@classmethod
def classmthd(*args):
return args
@staticmethod
def staticmthd(*args):
return args
# 1. Call classmethod without any arg
>>> Klaus.classmthd()
(__main__.Klaus,) # the class gets passed as the first argument
# 2. Call classmethod with 1 arg
>>> Klaus.classmthd('chumma')
(__main__.Klaus, 'chumma')
# 3. Call staticmethod without any arg
>>> Klaus.staticmthd()
()
# 4. Call staticmethod with 1 arg
>>> Klaus.staticmthd('chumma')
('chumma',)
Statik yöntem ile sınıf yöntemine ilişkin bir başka husus, kalıtımla ortaya çıkmaktadır. Aşağıdaki sınıfa sahip olduğunuzu varsayalım:
class Foo(object):
@staticmethod
def bar():
return "In Foo"
Ve sonra bar()
bir alt sınıfta geçersiz kılmak istiyorsunuz :
class Foo2(Foo):
@staticmethod
def bar():
return "In Foo2"
Bu işe yarar, ancak artık bar()
alt sınıftaki ( Foo2
) uygulamanın artık bu sınıfa özgü hiçbir şeyden yararlanamayacağını unutmayın. Örneğin, diyelim ki uygulanmasında kullanmak istediğiniz Foo2
adlı bir yöntem vardı :magic()
Foo2
bar()
class Foo2(Foo):
@staticmethod
def bar():
return "In Foo2"
@staticmethod
def magic():
return "Something useful you'd like to use in bar, but now can't"
Geçici çözüm burada aramak olurdu Foo2.magic()
içinde bar()
ama (adını o zaman kendini tekrar ediyorsun Foo2
değişikliklerle, bunu güncellemek için hatırlamak gerekecek bar()
yöntemi).
Bana göre, bu hafif bir ihlali açık / kapalı prensibinin , çünkü alınan bir karar Foo
türetilmiş bir sınıftaki ortak kodu yeniden düzenleme yeteneğinizi etkilemektedir (yani uzantıya daha az açıktır). Eğer bar()
bir vardı classmethod
biz iyi olurdu:
class Foo(object):
@classmethod
def bar(cls):
return "In Foo"
class Foo2(Foo):
@classmethod
def bar(cls):
return "In Foo2 " + cls.magic()
@classmethod
def magic(cls):
return "MAGIC"
print Foo2().bar()
verir: In Foo2 MAGIC
Temel farkı bir örnek kullanarak açıklamaya çalışacağım.
class A(object):
x = 0
def say_hi(self):
pass
@staticmethod
def say_hi_static():
pass
@classmethod
def say_hi_class(cls):
pass
def run_self(self):
self.x += 1
print self.x # outputs 1
self.say_hi()
self.say_hi_static()
self.say_hi_class()
@staticmethod
def run_static():
print A.x # outputs 0
# A.say_hi() # wrong
A.say_hi_static()
A.say_hi_class()
@classmethod
def run_class(cls):
print cls.x # outputs 0
# cls.say_hi() # wrong
cls.say_hi_static()
cls.say_hi_class()
1 - başlatmadan doğrudan statik ve sınıf yöntemlerini çağırabiliriz
# A.run_self() # wrong
A.run_static()
A.run_class()
2- Statik yöntem kendi yöntemini çağıramaz, ancak diğer statik ve sınıf yöntemlerini çağırabilir
3- Statik yöntem sınıfa aittir ve hiç nesne kullanmayacaktır.
4- Sınıf yöntemi bir nesneye değil, bir sınıfa bağlıdır.
@classmethod: o sınıfın oluşturulan tüm örnekleri için paylaşılan bir global erişim oluşturmak için kullanılabilir ..... birden fazla kullanıcı tarafından bir kayıt güncelleme gibi .... Ben de singletonları oluştururken ful kullanın bulundu ..: )
@static method: ilişkilendirilmiş sınıf veya örnekle hiçbir ilgisi yok ... ancak okunabilirlik için statik yöntem kullanabilir
Arasındaki farkı dikkate almak isteyebilirsiniz:
Class A:
def foo(): # no self parameter, no decorator
pass
ve
Class B:
@staticmethod
def foo(): # no self parameter
pass
Bu python2 ve python3 arasında değişti:
python2:
>>> A.foo()
TypeError
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()
python3:
>>> A.foo()
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()
Bu yüzden @staticmethod
sadece doğrudan sınıftan çağrılan yöntemler için python3'te isteğe bağlı hale gelmiştir. Bunları hem sınıftan hem de örnekten çağırmak istiyorsanız, yine de @staticmethod
dekoratörü kullanmanız gerekir .
Diğer vakalar unutbus cevabı ile iyi karşılanmıştır.
Sınıf yöntemi, tıpkı bir örnek yönteminin örneği alması gibi, sınıfı örtük ilk bağımsız değişken olarak alır. Sınıfın nesnesine değil sınıfa bağlı bir yöntemdir. Nesne örneğini değil, sınıfı işaret eden bir sınıf parametresini aldığından sınıfın durumuna erişebilir. Sınıfın tüm örnekleri için geçerli olacak bir sınıf durumunu değiştirebilir. Örneğin, tüm örneklere uygulanacak bir sınıf değişkenini değiştirebilir.
Öte yandan, statik yöntem sınıf yöntemlerine veya örnek yöntemlere kıyasla örtük bir ilk bağımsız değişken almaz. Sınıf durumuna erişemez veya sınıf durumunu değiştiremez. Sadece sınıfa aittir, çünkü tasarım açısından bu doğru yoldur. Ancak işlevsellik açısından, çalışma zamanında sınıfa bağlı değildir.
kılavuz olarak, statik yöntemleri yardımcı programlar olarak, sınıf yöntemlerini örneğin fabrika olarak kullanın. Veya belki bir singleton tanımlamak için. Örneklerin durumunu ve davranışını modellemek için örnek yöntemlerini kullanın.
Umarım netmişimdir!
Katkım @classmethod
, @staticmethod
bir örneğin dolaylı olarak a'yı nasıl çağırabileceği de dahil olmak üzere, ve örnek yöntemleri arasındaki farkı gösterir @staticmethod
. Ancak dolaylı @staticmethod
olarak bir örnekten a çağırmak yerine, onu özel yapmak daha "pitonik" olabilir. Özel bir yöntemden bir şey elde etmek burada gösterilmemiştir, ancak temel olarak aynı kavramdır.
#!python3
from os import system
system('cls')
# % % % % % % % % % % % % % % % % % % % %
class DemoClass(object):
# instance methods need a class instance and
# can access the instance through 'self'
def instance_method_1(self):
return 'called from inside the instance_method_1()'
def instance_method_2(self):
# an instance outside the class indirectly calls the static_method
return self.static_method() + ' via instance_method_2()'
# class methods don't need a class instance, they can't access the
# instance (self) but they have access to the class itself via 'cls'
@classmethod
def class_method(cls):
return 'called from inside the class_method()'
# static methods don't have access to 'cls' or 'self', they work like
# regular functions but belong to the class' namespace
@staticmethod
def static_method():
return 'called from inside the static_method()'
# % % % % % % % % % % % % % % % % % % % %
# works even if the class hasn't been instantiated
print(DemoClass.class_method() + '\n')
''' called from inside the class_method() '''
# works even if the class hasn't been instantiated
print(DemoClass.static_method() + '\n')
''' called from inside the static_method() '''
# % % % % % % % % % % % % % % % % % % % %
# >>>>> all methods types can be called on a class instance <<<<<
# instantiate the class
democlassObj = DemoClass()
# call instance_method_1()
print(democlassObj.instance_method_1() + '\n')
''' called from inside the instance_method_1() '''
# # indirectly call static_method through instance_method_2(), there's really no use
# for this since a @staticmethod can be called whether the class has been
# instantiated or not
print(democlassObj.instance_method_2() + '\n')
''' called from inside the static_method() via instance_method_2() '''
# call class_method()
print(democlassObj.class_method() + '\n')
''' called from inside the class_method() '''
# call static_method()
print(democlassObj.static_method())
''' called from inside the static_method() '''
"""
# whether the class is instantiated or not, this doesn't work
print(DemoClass.instance_method_1() + '\n')
'''
TypeError: TypeError: unbound method instancemethod() must be called with
DemoClass instance as first argument (got nothing instead)
'''
"""
Sınıf yöntemleri, adından da anlaşılacağı gibi, nesnelerde değil sınıflarda değişiklik yapmak için kullanılır. Sınıflarda değişiklik yapmak için, sınıfları bu şekilde güncellediğiniz için sınıf özniteliklerini değiştirir (nesne özniteliklerini değil). Sınıf yöntemlerinin sınıfı (geleneksel olarak 'cls' ile gösterilen) ilk argüman olarak almasının nedeni budur.
class A(object):
m=54
@classmethod
def class_method(cls):
print "m is %d" % cls.m
Statik yöntemler, sınıfa bağlı olmayan işlevleri yerine getirmek için kullanılır, yani sınıf değişkenlerini okumaz veya yazmazlar. Bu nedenle, statik yöntemler sınıfları bağımsız değişken olarak almaz. Sınıfların doğrudan sınıfın amacı ile ilgili olmayan işlevleri yerine getirebilmesi için kullanılırlar.
class X(object):
m=54 #will not be referenced
@staticmethod
def static_method():
print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."
@Staticmethod kelimesini kelimesine göre analiz et farklı bilgiler sağlayarak .
Bir sınıfın normal yöntemi , örneği ilk argüman olarak alan kapalı bir dinamik yöntemdir.
Bunun aksine, bir statik yöntem örneği ilk argüman olarak almaz, buna 'statik' denir .
Statik yöntem aslında sınıf tanımının dışındaki normal bir işlevdir.
Neyse ki uygulandığı yere daha yakın durmak için sınıfa gruplandırılır ya da bulmak için gezinebilirsiniz.
Bence sadece Python versiyonunu veriyorum staticmethod
veclassmethod
aralarındaki farkı dil düzeyinde anlamaya yardımcı olmak.
Her ikisi de veri olmayan tanımlayıcılardır ( Önce tanımlayıcılara aşina iseniz bunları anlamak daha kolay olacaktır ).
class StaticMethod(object):
"Emulate PyStaticMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
def __get__(self, obj, objtype=None):
return self.f
class ClassMethod(object):
"Emulate PyClassMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
def __get__(self, obj, cls=None):
def inner(*args, **kwargs):
if cls is None:
cls = type(obj)
return self.f(cls, *args, **kwargs)
return inner
staticmethod, nesnenin, sınıfın veya miras hiyerarşisindeki üst sınıfların özniteliklerine erişemez. Doğrudan sınıfta çağrılabilir (nesne oluşturmadan).
classmethod nesnesinin niteliklerine erişemez. Ancak, miras hiyerarşisinde sınıfın ve üst sınıfların özelliklerine erişebilir. Doğrudan sınıfta çağrılabilir (nesne oluşturmadan). Nesneye çağrılırsa, erişmeyen self.<attribute(s)>
ve erişmeyen normal yöntemle aynıdır.self.__class__.<attribute(s)>
yalnızca .
Bir sınıfımız olduğunu düşünün b=2
, bir nesne yaratacağız ve b=4
bunu içinde yeniden ayarlayacağız . Staticmethod öncekinden hiçbir şeye erişemez. Classmethod .b==2
sadece üzerinden erişebilir cls.b
. Normal yöntem her ikisine de erişebilir: .b==4
üzerinden self.b
ve .b==2
üzerinden self.__class__.b
.
KISS stilini takip edebiliriz (basit, aptalca): Statik yöntemler ve sınıf yöntemleri kullanmayın, sınıfları somutlaştırmadan kullanmayın, yalnızca nesnenin niteliklerine erişin self.attribute(s)
. OOP'un bu şekilde uygulandığı diller var ve bence kötü bir fikir değil. :)
İPython'daki diğer yöntemlerin hızlı bir şekilde kesilmesi, @staticmethod
marjinal performans kazançları (nanosaniye cinsinden) verdiğini ortaya çıkarır , ancak aksi takdirde hiçbir işlev görmüyor gibi görünüyor. Ayrıca, herhangi bir performans kazancı, yöntemin,staticmethod()
derleme sırasında (bir komut dosyası çalıştırdığınızda herhangi bir kod yürütülmesinden önce gerçekleşir) .
Kod okunabilirliği açısından @staticmethod
, yönteminiz nanosaniyelerin önemli olduğu iş yükleri için kullanılmadıkça kaçınırım .