เป็นไปได้ไหมที่จะมีเมธอดสแตติกใน Python ที่ฉันสามารถเรียกได้โดยไม่ต้องกำหนดค่าเริ่มต้นของคลาสเช่น:
ClassName.static_method()
เป็นไปได้ไหมที่จะมีเมธอดสแตติกใน Python ที่ฉันสามารถเรียกได้โดยไม่ต้องกำหนดค่าเริ่มต้นของคลาสเช่น:
ClassName.static_method()
คำตอบ:
อ๋อใช้StaticMethodมัณฑนากร
class MyClass(object):
@staticmethod
def the_static_method(x):
print(x)
MyClass.the_static_method(2) # outputs 2
โปรดทราบว่าบางรหัสอาจใช้วิธีการเก่าของการกำหนดวิธีการคงที่โดยใช้staticmethod
เป็นฟังก์ชั่นมากกว่ามัณฑนากร ควรใช้เฉพาะเมื่อคุณต้องสนับสนุน Python เวอร์ชันโบราณ (2.2 และ 2.3)
class MyClass(object):
def the_static_method(x):
print(x)
the_static_method = staticmethod(the_static_method)
MyClass.the_static_method(2) # outputs 2
นี่เหมือนกับตัวอย่างแรกทั้งหมด (โดยใช้@staticmethod
) เพียงแค่ไม่ใช้ไวยากรณ์ของมัณฑนากรที่ดี
ในที่สุดใช้staticmethod()
เท่าที่จำเป็น! มีสถานการณ์น้อยมากที่จำเป็นต้องใช้วิธีการคงที่ใน Python และฉันเคยเห็นพวกเขาใช้หลายครั้งซึ่งฟังก์ชั่น "ระดับบนสุด" แยกต่างหากจะชัดเจนขึ้น
ต่อไปนี้เป็นคำต่อคำจากเอกสาร :
วิธีการคงที่ไม่ได้รับการโต้แย้งครั้งแรกโดยปริยาย ในการประกาศเมธอดสแตติกให้ใช้สำนวนนี้:
class C: @staticmethod def f(arg1, arg2, ...): ...
รูปแบบ @staticmethod เป็นตัวตกแต่งฟังก์ชั่น- ดูคำอธิบายของคำจำกัดความของฟังก์ชั่นในคำจำกัดความของฟังก์ชั่นสำหรับรายละเอียด
มันสามารถเรียกได้ทั้งในชั้นเรียน (เช่น
C.f()
) หรือในอินสแตนซ์ (เช่นC().f()
) อินสแตนซ์ถูกละเว้นยกเว้นคลาสของมันวิธีการคงที่ใน Python คล้ายกับที่พบใน Java หรือ C ++
classmethod()
สำหรับแนวความคิดขั้นสูงเพิ่มเติมโปรดดูที่สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการคงปรึกษาเอกสารเกี่ยวกับลำดับชั้นมาตรฐานชนิดในลำดับชั้นมาตรฐานชนิด
ใหม่ในเวอร์ชัน 2.2
เปลี่ยนเป็นเวอร์ชั่น 2.4: เพิ่มฟังก์ชั่นไวยากรณ์มัณฑนากร
ClassName.methodName()
ว่ามันเป็นสแตติกและจากนั้นself
จะไม่มีการจัดเตรียมเมธอด ดังที่คุณกล่าวว่าจะยังสามารถเรียกวิธีนี้ได้เช่นClassInstance.methodName()
กันและself
จะให้เป็นพารามิเตอร์แรกโดยไม่คำนึงถึงชื่อ
ผมคิดว่าสตีเว่นเป็นจริงที่ถูกต้อง ในการตอบคำถามเดิมจากนั้นในการตั้งค่าวิธีการเรียนเพียงแค่สมมติว่าอาร์กิวเมนต์แรกไม่ได้เป็นอินสแตนซ์การโทรและจากนั้นตรวจสอบให้แน่ใจว่าคุณเรียกวิธีการจากชั้นเรียนเท่านั้น
(โปรดทราบว่าคำตอบนี้หมายถึง Python 3.x ใน Python 2.x คุณจะได้รับTypeError
สำหรับการเรียกใช้เมธอดในคลาสเอง)
ตัวอย่างเช่น:
class Dog:
count = 0 # this is a class variable
dogs = [] # this is a class variable
def __init__(self, name):
self.name = name #self.name is an instance variable
Dog.count += 1
Dog.dogs.append(name)
def bark(self, n): # this is an instance method
print("{} says: {}".format(self.name, "woof! " * n))
def rollCall(n): #this is implicitly a class method (see comments below)
print("There are {} dogs.".format(Dog.count))
if n >= len(Dog.dogs) or n < 0:
print("They are:")
for dog in Dog.dogs:
print(" {}".format(dog))
else:
print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))
fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
ในรหัสนี้เมธอด "rollCall" สันนิษฐานว่าอาร์กิวเมนต์แรกไม่ใช่อินสแตนซ์ (อย่างที่มันจะเป็นถ้ามันถูกเรียกโดยอินสแตนซ์แทนที่จะเป็นคลาส) ตราบใดที่มีการเรียก "rollCall" จากคลาสแทนที่จะเป็นอินสแตนซ์รหัสจะทำงานได้ดี หากเราพยายามโทรหา "rollCall" จากตัวอย่างเช่น:
rex.rollCall(-1)
อย่างไรก็ตามมันจะทำให้เกิดข้อยกเว้นที่จะยกขึ้นเพราะมันจะส่งสองข้อโต้แย้ง: ตัวเองและ -1 และ "rollCall" ถูกกำหนดให้ยอมรับเพียงหนึ่งอาร์กิวเมนต์
อนึ่ง rex.rollCall () จะส่งจำนวนอาร์กิวเมนต์ที่ถูกต้อง แต่ก็จะทำให้เกิดข้อยกเว้นที่จะยกขึ้นเพราะตอนนี้ n จะเป็นตัวแทนของอินสแตนซ์ Dog (เช่น rex) เมื่อฟังก์ชั่นคาดว่าจะเป็นตัวเลข
นี่คือที่มาของการตกแต่ง: หากเรานำหน้าวิธี "rollCall" ด้วย
@staticmethod
จากนั้นโดยการระบุอย่างชัดเจนว่าวิธีการเป็นแบบคงที่เราสามารถเรียกมันได้จากอินสแตนซ์ ตอนนี้
rex.rollCall(-1)
จะทำงาน. การแทรก @staticmethod ก่อนคำนิยามวิธีการจากนั้นหยุดอินสแตนซ์จากการส่งตัวเองเป็นข้อโต้แย้ง
คุณสามารถตรวจสอบสิ่งนี้ได้โดยลองใช้รหัสต่อไปนี้โดยใช้และไม่มีบรรทัด @staticmethod ที่ใส่ความคิดเห็นไว้
class Dog:
count = 0 # this is a class variable
dogs = [] # this is a class variable
def __init__(self, name):
self.name = name #self.name is an instance variable
Dog.count += 1
Dog.dogs.append(name)
def bark(self, n): # this is an instance method
print("{} says: {}".format(self.name, "woof! " * n))
@staticmethod
def rollCall(n):
print("There are {} dogs.".format(Dog.count))
if n >= len(Dog.dogs) or n < 0:
print("They are:")
for dog in Dog.dogs:
print(" {}".format(dog))
else:
print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))
fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
rex.rollCall(-1)
TypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead)
T.my_static_method()
หรือtype(my_t_instance).my_static_method()
เนื่องจากเป็นที่ชัดเจนและทำให้ชัดเจนทันทีว่าฉันเรียกวิธีคงที่
ใช่ตรวจสอบStaticMethodมัณฑนากร:
>>> class C:
... @staticmethod
... def hello():
... print "Hello World"
...
>>> C.hello()
Hello World
คุณไม่จำเป็นต้องใช้@staticmethod
มัณฑนากร เพียงแค่ประกาศเมธอด (ที่ไม่ได้คาดหวังว่าพารามิเตอร์ของตนเอง) และเรียกมันจากชั้นเรียน มัณฑนากรมีเฉพาะในกรณีที่คุณต้องการโทรจากอินสแตนซ์เช่นกัน (ซึ่งไม่ใช่สิ่งที่คุณต้องการจะทำ)
ส่วนใหญ่คุณเพียงแค่ใช้ฟังก์ชั่น แต่ ...
class Dummy: def static1(): print "hello from static1" @staticmethod def static2(): print "hello from static2" Dummy.static2() Dummy.static1()
เอาต์พุต: สวัสดีจาก static2 การติดตามย้อนกลับ <การโทรล่าสุดครั้งล่าสุด>: ไฟล์ "ll.py", บรรทัดที่ 46 ใน <module> Dummy.static1 () TypeError: วิธีที่ไม่ถูกต้อง static1 () เรียกว่ามีอินสแตนซ์ Dummy เป็นอาร์กิวเมนต์แรก (มีอะไรแทน)
self
เป็นอาร์กิวเมนต์แรกเว้นแต่ว่าคุณจะไม่บอก (ดู: มัณฑนากร)
self
อ้างอิงอย่างเหมาะสมขึ้นอยู่กับว่ามันถูกเรียกว่าอย่างไร กรณีการทดสอบ: pastebin.com/12DDV7DB
staticmethod
มัณฑนากรช่วยให้หนึ่งเพื่อเรียกใช้ฟังก์ชันทั้งในชั้นเรียนและอินสแตนซ์ (แก้ปัญหานี้ล้มเหลวเมื่อมีการเรียกฟังก์ชั่นอินสแตนซ์)
class C: def callme(): print('called'); C.callme()
วิธีการคงที่ในงูหลาม?
เป็นไปได้หรือไม่ที่จะมีวิธีการคงที่ใน Python เพื่อให้ฉันสามารถเรียกพวกเขาโดยไม่ต้องเริ่มต้นชั้นเรียนเช่น:
ClassName.StaticMethod()
ใช่วิธีการคงที่สามารถสร้างเช่นนี้ (แม้ว่าจะเป็นPythonicเล็กน้อยที่จะใช้ขีดเส้นใต้แทน CamelCase สำหรับวิธีการ):
class ClassName(object):
@staticmethod
def static_method(kwarg1=None):
'''return a value that is a function of kwarg1'''
ข้างต้นใช้ไวยากรณ์มัณฑนากร ไวยากรณ์นี้เทียบเท่ากับ
class ClassName(object):
def static_method(kwarg1=None):
'''return a value that is a function of kwarg1'''
static_method = staticmethod(static_method)
สามารถใช้งานได้ตามที่อธิบายไว้:
ClassName.static_method()
ตัวอย่าง builtin ของวิธีการคงที่อยู่str.maketrans()
ใน Python 3 ซึ่งเป็นฟังก์ชั่นในstring
โมดูลใน Python 2
ตัวเลือกอื่นที่สามารถใช้ตามที่คุณอธิบายได้คือความclassmethod
แตกต่างคือเมธอด class รับคลาสเป็นอาร์กิวเมนต์แรกโดยปริยายและถ้าคลาสย่อยแล้วมันจะได้รับคลาสย่อยเป็นอาร์กิวเมนต์แรกโดยปริยาย
class ClassName(object):
@classmethod
def class_method(cls, kwarg1=None):
'''return a value that is a function of the class and kwarg1'''
โปรดทราบว่าcls
ไม่ใช่ชื่อที่จำเป็นสำหรับอาร์กิวเมนต์แรก แต่ตัวแปลงสัญญาณ Python ที่มีประสบการณ์ส่วนใหญ่จะพิจารณาว่าทำได้ไม่ดีหากคุณใช้สิ่งอื่น
โดยทั่วไปจะใช้สิ่งเหล่านี้เป็นตัวสร้างทางเลือก
new_instance = ClassName.class_method()
ตัวอย่าง builtin คือdict.fromkeys()
:
new_dict = dict.fromkeys(['key1', 'key2'])
นอกเหนือจากลักษณะเฉพาะของวิธีการที่วัตถุวิธีการทำงานแบบคงที่มีความงามบางชนิดที่คุณสามารถใช้กับพวกเขาเมื่อมันมาถึงการจัดระเบียบรหัสระดับโมดูลของคุณ
# garden.py
def trim(a):
pass
def strip(a):
pass
def bunch(a, b):
pass
def _foo(foo):
pass
class powertools(object):
"""
Provides much regarded gardening power tools.
"""
@staticmethod
def answer_to_the_ultimate_question_of_life_the_universe_and_everything():
return 42
@staticmethod
def random():
return 13
@staticmethod
def promise():
return True
def _bar(baz, quux):
pass
class _Dice(object):
pass
class _6d(_Dice):
pass
class _12d(_Dice):
pass
class _Smarter:
pass
class _MagicalPonies:
pass
class _Samurai:
pass
class Foo(_6d, _Samurai):
pass
class Bar(_12d, _Smarter, _MagicalPonies):
pass
...
# tests.py
import unittest
import garden
class GardenTests(unittest.TestCase):
pass
class PowertoolsTests(unittest.TestCase):
pass
class FooTests(unittest.TestCase):
pass
class BarTests(unittest.TestCase):
pass
...
# interactive.py
from garden import trim, bunch, Foo
f = trim(Foo())
bunch(f, Foo())
...
# my_garden.py
import garden
from garden import powertools
class _Cowboy(garden._Samurai):
def hit():
return powertools.promise() and powertools.random() or 0
class Foo(_Cowboy, garden.Foo):
pass
ตอนนี้กลายเป็นบิตง่ายขึ้นและการจัดทำเอกสารด้วยตนเองในบริบทที่องค์ประกอบบางอย่างมีความหมายที่จะใช้และมันออกมาอย่างยอดเยี่ยมสำหรับการตั้งชื่อกรณีทดสอบที่แตกต่างกันเช่นเดียวกับวิธีการตรงไปตรงมา .
ฉันมักจะพบว่าใช้วิธีการนี้ในการจัดระเบียบรหัสยูทิลิตี้ของโครงการ บ่อยครั้งที่ผู้คนรีบเร่งและสร้างutils
แพ็คเกจและจบลงด้วย 9 โมดูลซึ่งหนึ่งในนั้นมี 120 LOC และที่เหลือเป็นสองโหล LOC ที่ดีที่สุด ฉันชอบที่จะเริ่มต้นด้วยสิ่งนี้และแปลงเป็นแพ็คเกจและสร้างโมดูลสำหรับสัตว์ที่สมควรได้รับอย่างแท้จริงเท่านั้น:
# utils.py
class socket(object):
@staticmethod
def check_if_port_available(port):
pass
@staticmethod
def get_free_port(port)
pass
class image(object):
@staticmethod
def to_rgb(image):
pass
@staticmethod
def to_cmyk(image):
pass
บางทีตัวเลือกที่ง่ายที่สุดคือการใส่ฟังก์ชั่นเหล่านั้นนอกคลาส:
class Dog(object):
def __init__(self, name):
self.name = name
def bark(self):
if self.name == "Doggy":
return barking_sound()
else:
return "yip yip"
def barking_sound():
return "woof woof"
การใช้วิธีการนี้ฟังก์ชันที่แก้ไขหรือใช้สถานะวัตถุภายใน (มีผลข้างเคียง) สามารถเก็บไว้ในคลาสได้และสามารถย้ายฟังก์ชั่นยูทิลิตี้ที่ใช้ซ้ำได้ภายนอก
dogs.py
สมมติว่าไฟล์นี้จะเรียกว่า หากต้องการใช้เหล่านี้ที่คุณต้องการเรียกแทนdogs.barking_sound()
dogs.Dog.barking_sound
ถ้าคุณต้องการจริงๆวิธีคงเป็นส่วนหนึ่งของชั้นเรียนคุณสามารถใช้StaticMethodมัณฑนากร
ดังนั้นวิธีการคงที่เป็นวิธีการที่สามารถเรียกได้โดยไม่ต้องสร้างวัตถุของชั้นเรียน ตัวอย่างเช่น :-
@staticmethod
def add(a, b):
return a + b
b = A.add(12,12)
print b
ในตัวอย่างข้างต้นวิธีการที่add
ถูกเรียกโดยชื่อชั้นA
ไม่ใช่ชื่อวัตถุ
Python Static method สามารถสร้างได้สองวิธี
การใช้ staticmethod ()
class Arithmetic:
def add(x, y):
return x + y
# create add static method
Arithmetic.add = staticmethod(Arithmetic.add)
print('Result:', Arithmetic.add(15, 10))
เอาท์พุท:
ผลลัพธ์: 25
ใช้ @ staticmethod
class Arithmetic:
# create add static method
@staticmethod
def add(x, y):
return x + y
print('Result:', Arithmetic.add(15, 10))
เอาท์พุท:
ผลลัพธ์: 25
ฉันพบคำถามนี้เป็นครั้งคราว กรณีการใช้งานและตัวอย่างที่ฉันชอบคือ:
jeffs@jeffs-desktop:/home/jeffs $ python36
Python 3.6.1 (default, Sep 7 2017, 16:36:03)
[GCC 6.3.0 20170406] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cmath
>>> print(cmath.sqrt(-4))
2j
>>>
>>> dir(cmath)
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cos', 'cosh', 'e', 'exp', 'inf', 'infj', 'isclose', 'isfinite', 'isinf', 'isnan', 'log', 'log10', 'nan', 'nanj', 'phase', 'pi', 'polar', 'rect', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau']
>>>
มันไม่สมเหตุสมผลเลยที่จะสร้างวัตถุของคลาส cmath เนื่องจากไม่มีสถานะในวัตถุ cmath อย่างไรก็ตาม cmath เป็นชุดของวิธีการที่เกี่ยวข้องทั้งหมดในบางวิธี ในตัวอย่างของฉันข้างต้นฟังก์ชันทั้งหมดใน cmath กระทำกับตัวเลขที่ซับซ้อนในบางวิธี
@staticmethod
ตกแต่งหรือใช้ตัวชี้ฟังก์ชั่นเมื่อคุณสามารถหลีกเลี่ยงself
พารามิเตอร์แรกได้ สำหรับวัตถุa
คุณจะไม่สามารถโทรออกa.your_static_method()
ได้ซึ่งได้รับอนุญาตในภาษาอื่น ๆ แต่ก็ถือว่าเป็นการปฏิบัติที่ไม่ดีและคอมไพเลอร์เตือนเสมอเกี่ยวกับมัน