"วิธีการเรียน" และ "วิธีการแบบอินสแตนซ์" ใน Python คืออะไร


37

มีการพูดคุยกันในการแชทเกี่ยวกับคำถาม (คำถามนั้นไม่เกี่ยวข้องกับคำถามนี้) ซึ่งได้เปิดเผยว่าฉันอาจไม่รู้จัก Python แต่อย่างใด

ในใจของฉันถึงแม้ว่าคำศัพท์จะแตกต่างกันไปในแต่ละภาษา

  • [ฟรี] ฟังก์ชั่น
  • วิธีการคงที่ / ฟังก์ชั่นสมาชิกคงที่
  • วิธีการไม่คงที่ / ฟังก์ชั่นสมาชิกคงที่

เห็นได้ชัดว่าใน Python มีฟังก์ชั่นอีกประเภทหนึ่งที่ไม่เหมาะกับหมวดหมู่ข้างต้นซึ่งเป็นวิธีการหนึ่ง แต่ "ไม่รู้จักคลาส"

"วิธีการเรียน" และ "วิธีการเช่น" ใน Python คืออะไร?


1
หากใครสนใจสนทนาสนทนาเริ่มที่นี่: chat.stackexchange.com/transcript/message/26479002#26479002
yannis

1
IMO ให้คำตอบที่ดีกว่าโดยเว็บไซต์ stackexchange อื่น: stackoverflow.com/questions/136097/…
Trevor Boyd Smith

FYI มีการเชื่อมโยงไว้ที่ด้านล่างของที่ยอมรับ ... แต่ฉันคิดว่าหลายคนจะพลาดการเชื่อมโยงหรือไม่เคยไปถึงมันดังนั้นฉันจึงคัดลอกที่นี่
เทรเวอร์บอยด์สมิ ธ

คำตอบ:


49

คำตอบสั้น ๆ

  • วิธีการอินสแตนซ์รู้ตัวอย่างของมัน
  • วิธีการเรียนรู้ของชั้นเรียน
  • วิธีการคงไม่ทราบชั้นเรียนหรืออินสแตนซ์ของมัน

คำตอบที่ยาว

วิธีการเรียน

วิธีการเรียนเป็นสิ่งหนึ่งที่อยู่ในชั้นเรียนเป็นทั้ง ไม่ต้องการอินสแตนซ์ แต่คลาสจะถูกส่งโดยอัตโนมัติเป็นอาร์กิวเมนต์แรก วิธีการเรียนที่มีการประกาศด้วย@classmethodมัณฑนากร

ตัวอย่างเช่น:

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

วิธีการอินสแตนซ์

ในทางตรงกันข้ามวิธีการอินสแตนซ์ ต้องมีอินสแตนซ์เพื่อที่จะเรียกมันและไม่ต้องใช้มัณฑนากร นี่เป็นวิธีการที่พบได้บ่อยที่สุด

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

(หมายเหตุ: ข้างต้นคือด้วย python3; กับ python2 คุณจะได้รับข้อผิดพลาดที่แตกต่างกันเล็กน้อย)

วิธีการคงที่

วิธีคงคล้ายกับวิธีการเรียน แต่จะไม่ได้รับวัตถุชั้นเป็นพารามิเตอร์อัตโนมัติ มันถูกสร้างขึ้นโดยใช้@staticmethodมัณฑนากร

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

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

ลิงค์เอกสาร

นี่คือลิงค์ไปยังเอกสาร python3 ที่เกี่ยวข้อง:

เอกสารข้อมูลแบบนี้จะพูดเกี่ยวกับความแตกต่างระหว่างวิธีการเรียนและวิธีการคงมี:

วัตถุวิธีการแบบคงที่วัตถุวิธีการแบบคงที่มีวิธีการเอาชนะการเปลี่ยนแปลงของฟังก์ชั่นวัตถุวัตถุวิธีการอธิบายไว้ข้างต้น วัตถุวิธีการคงที่เป็น wrapper รอบ ๆ วัตถุอื่น ๆ มักจะเป็นวัตถุที่ผู้ใช้กำหนด เมื่อวัตถุวิธีการแบบคงที่จะถูกดึงจากคลาสหรืออินสแตนซ์ของชั้นเรียนวัตถุที่ส่งคืนจริงคือวัตถุห่อซึ่งไม่ต้องมีการเปลี่ยนแปลงเพิ่มเติม วัตถุเมธอดแบบสแตติกไม่ได้เรียกตัวเองแม้ว่าวัตถุที่พวกมันห่อมักจะเป็น วัตถุวิธีการคงที่ถูกสร้างขึ้นโดยตัวสร้าง staticmethod () ในตัว

วัตถุวิธี การเรียนวัตถุวัตถุวิธีการเรียนเช่นวัตถุวิธีการแบบคงที่เป็นเสื้อคลุมรอบวัตถุอื่นที่เปลี่ยนแปลงวิธีการที่วัตถุนั้นจะถูกดึงจากชั้นเรียนและอินสแตนซ์ชั้นเรียน พฤติกรรมของวัตถุวิธีการเรียนในการดึงดังกล่าวอธิบายไว้ข้างต้นภายใต้ "วิธีการที่ผู้ใช้กำหนด" วัตถุวิธีการเรียนที่ถูกสร้างขึ้นโดยตัวสร้าง classmethod () ในตัว

คำถามที่เกี่ยวข้อง


4
@LightnessRacesinOrbit: ฉันไม่คิดว่าจะใช้วิธีการคงที่โดยเฉพาะอย่างยิ่งในหลาม การใช้ระบบของฉันเป็นตัวอย่างแบบสุ่มเมื่อฉันค้นหาแพ็คเกจทั้งหมดที่ฉันติดตั้งเพียงประมาณ 1% ของวิธีการทั้งหมดเป็นวิธีแบบคงที่ (ซึ่งตรงไปตรงมามากกว่าที่ฉันคาดไว้)
ไบรอัน Oakley

1
"วิธีการคงที่" มักจะมีกลิ่นรหัสและท้อแท้โดยคู่มือสไตล์ Gogole Python
9000

3
ฉันคิดว่าคำตอบจะดีขึ้นหากดึงความสนใจไปที่คลาสย่อยซึ่งเป็นที่ที่วิธีการในชั้นเรียนได้รับประโยชน์บางอย่าง
Winston Ewert

1
@ user2357112: ฉันก็นับกรณีของนับแล้วทุกกรณี"^ def(" @staticmethodไม่มีหลักวิทยาศาสตร์มาก แต่อาจอยู่ในสวนเบสบอล
Bryan Oakley

2
@Kashyap: TL; DR ใช้กับย่อหน้าแรก ฉันคิดว่ามันใช้งานได้ดีกว่าบนสุดด้านล่าง
ไบรอัน Oakley

8

"วิธีการเรียน" และ "วิธีการแบบอินสแตนซ์" ใน Python คืออะไร

  • "วิธีการอินสแตนซ์" ใช้ข้อมูลที่มีอยู่ในอินสแตนซ์ที่จะคิดออกว่าจะคืนค่าใด (หรือผลข้างเคียงที่จะทำ) เหล่านี้เป็นเรื่องธรรมดามาก

  • "วิธีการเรียน" ใช้ข้อมูลเกี่ยวกับชั้นเรียน (และไม่ใช่ตัวอย่างของชั้นเรียนนั้น) เพื่อส่งผลกระทบต่อสิ่งที่ทำ (โดยปกติแล้วพวกเขาจะใช้ในการสร้างอินสแตนซ์ใหม่เป็นตัวสร้างทางเลือก

  • "วิธีการคงที่" ไม่ได้ใช้ข้อมูลใด ๆ เกี่ยวกับชั้นเรียนหรืออินสแตนซ์ในการคำนวณสิ่งที่มันทำ มันมักจะเป็นเพียงในชั้นเรียนเพื่อความสะดวก (เช่นนี้สิ่งเหล่านี้ก็ไม่ธรรมดาเหมือนกัน)

ฟังก์ชั่นของ X

จำคลาสคณิตศาสตร์ "y เป็นฟังก์ชันของ x, f(x)" ลองใช้ในรหัส:

y = function(x)

โดยนัยดังกล่าวข้างต้นก็คือตั้งแต่xอาจมีการเปลี่ยนแปลงyอาจมีการเปลี่ยนแปลงเมื่อมีxการเปลี่ยนแปลง นี่คือสิ่งที่มีความหมายเมื่อเราพูดว่า " yเป็นฟังก์ชั่นของx"

สิ่งที่จะyได้รับเมื่อzเป็น1? 2? 'FooBarBaz'?

yไม่ใช่หน้าที่ของzดังนั้นzสามารถเป็นอะไรก็ได้และไม่ส่งผลกระทบต่อผลลัพธ์ของฟังก์ชันสมมติว่าเราfunctionเป็นฟังก์ชันบริสุทธิ์ (ถ้ามันเข้าถึงzเป็นตัวแปรทั่วโลกแสดงว่ามันไม่ใช่ฟังก์ชั่นแท้ - นี่คือสิ่งที่มีความหมายโดยความบริสุทธิ์ในการใช้งาน)

จำไว้ข้างต้นในขณะที่คุณอ่านคำอธิบายต่อไปนี้:

วิธีการอินสแตนซ์

วิธีการเช่นฟังก์ชั่นที่มีฟังก์ชั่นของอินสแตนซ์ ฟังก์ชั่นยอมรับอินสแตนซ์โดยนัยว่าเป็นอาร์กิวเมนต์ของมันและอินสแตนซ์จะถูกใช้โดยฟังก์ชั่นเพื่อกำหนดผลลัพธ์ของฟังก์ชั่น

ตัวอย่างในตัวของวิธีการอินสแตนซ์คือ str.lower:

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

str.lower ถูกเรียกบนอินสแตนซ์ของสตริงและจะใช้ข้อมูลที่มีอยู่ในอินสแตนซ์เพื่อค้นหาว่าสายอักขระใหม่ที่จะส่งกลับ

วิธีการเรียน:

จำไว้ว่าใน Python ทุกอย่างเป็นวัตถุ นั่นหมายความว่าคลาสเป็นวัตถุและสามารถส่งผ่านเป็นอาร์กิวเมนต์ไปยังฟังก์ชันได้

วิธีการเรียนเป็นฟังก์ชั่นที่เป็นฟังก์ชั่นของการเรียน มันยอมรับระดับเป็นข้อโต้แย้งไป

ตัวอย่าง builtin คือdict.fromkeys:

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

ฟังก์ชั่นโดยปริยายรู้ระดับของตัวเองฟังก์ชั่นการใช้คลาสที่มีผลต่อการส่งออกของฟังก์ชั่นและมันจะสร้างหนึ่งใหม่ของชั้นเรียนนั้นจาก iterable OrderedDict สาธิตสิ่งนี้เมื่อใช้วิธีการเดียวกัน:

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

เมธอดคลาสใช้ข้อมูลเกี่ยวกับคลาส (และไม่ใช่อินสแตนซ์ของคลาสนั้น) เพื่อส่งผลต่อประเภทของคลาสที่จะส่งคืน

วิธีการคงที่

คุณพูดถึงวิธีการที่ "ไม่รู้จักคลาส" - นี่เป็นวิธีการคงที่ใน Python มันเป็นเพียงเพื่อความสะดวกในการเรียนวัตถุ มันอาจจะเป็นฟังก์ชั่นแยกต่างหากในโมดูลอื่น แต่ลายเซ็นการโทรนั้นจะเหมือนกัน

วิธีการคงที่เป็นฟังก์ชั่นของทั้งชั้นเรียนและวัตถุ

ตัวอย่างในตัวของวิธีการคงที่คือ str.maketrans จาก Python 3

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

ได้รับข้อโต้แย้งสองสามมันทำให้พจนานุกรมที่ไม่ใช่ฟังก์ชั่นของชั้นเรียนของมัน

สะดวกเพราะstrมีอยู่ในเนมสเปซส่วนกลางเสมอดังนั้นคุณจึงสามารถใช้กับฟังก์ชั่นแปลได้อย่างง่ายดาย:

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

ใน Python 2 คุณต้องเข้าถึงจากstringโมดูล:

>>> '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'

ตัวอย่าง

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

ขอยกตัวอย่าง:

>>> instance = AClass()

ตอนนี้อินสแตนซ์สามารถเรียกใช้เมธอดทั้งหมดได้:

>>> 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)

แต่คลาสมักไม่ได้ตั้งใจจะเรียกใช้วิธีการอินสแตนซ์แม้ว่าจะคาดว่าจะเรียกคนอื่น ๆ :

>>> 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'

คุณจะต้องส่งผ่านอินสแตนซ์ให้ชัดเจนเพื่อเรียกเมธอดอินสแตนซ์:

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

"นี่เป็นวิธีการคงที่ใน Python มันเป็นเพียงการแนบเพื่อความสะดวกในการเรียนวัตถุมันอาจเป็นฟังก์ชั่นแยกต่างหากในโมดูลอื่น แต่ลายเซ็นการโทรของมันจะเหมือนกัน" ดูเหมือนสับสนมากกว่าสะดวก ทำไมคุณต้องแนบฟังก์ชั่นเข้ากับคลาสหากร่างกายของมันไม่มีแนวคิดของคลาสนั้น
การแข่งขัน Lightness กับโมนิก้า

@LightnessRacesinOrbit ฉันได้อธิบายอย่างละเอียดในแต่ละประเด็นแล้ว
Aaron Hall

ส่วนตัววิธีการที่ผมได้ดูเสมอที่มันเป็นว่าวิธีการเช่นเป็นงานบนอินสแตนซ์โดยเฉพาะอย่างยิ่งวิธีการเรียนคือการเรียงลำดับของคอนสตรัค (เพื่อความสะดวกอะไรที่ชอบMyClass(1,2,3)แต่ชอบMyClass.get_special(1,2,3)) และวิธีการคงเป็นเพียงแค่ เป็นฟังก์ชั่นปกติที่สามารถยืนอยู่คนเดียวได้
Zizouz212

ใช่ classmethods มักจะใช้สำหรับตัวสร้างทางเลือก (ดูตัวอย่าง dict.fromkeys ของฉันด้านบนดูที่ซอร์สโค้ด pandas.DataFrame ด้วย) แต่นั่นไม่ใช่ลักษณะที่กำหนด บางครั้งฉันเพียงต้องการเข้าถึงข้อมูลที่เก็บไว้ในระดับชั้นเรียนจากวิธีการโดยไม่ต้องเข้าถึงอินสแตนซ์ หากคุณกำลังโทรหา type (self) (หรือแย่กว่านั้นคือ self .__ class__) และไม่ได้ใช้ self โดยตรงในวิธีการอินสแตนซ์นั่นเป็นสัญญาณที่ดีที่คุณควรพิจารณาให้เป็น classmethod เนื่องจาก classmethods ไม่ต้องการอินสแตนซ์จึงทำให้ unittest ง่ายขึ้น
Aaron Hall

4
  • เป็น "วิธีการเช่น" เป็นวิธีการที่ได้รับผ่านวัตถุเช่นเป็นพารามิเตอร์แรกของ บริษัท selfซึ่งโดยการประชุมที่เรียกว่า นี่คือค่าเริ่มต้น

  • "วิธีการคงที่" เป็นวิธีการที่ไม่มีselfพารามิเตอร์เริ่มต้น นี้จะดำเนินการกับมัณฑนากร @staticmethod

  • A "วิธีการเรียน" เป็นวิธีการที่พารามิเตอร์เริ่มต้นไม่ได้เป็นวัตถุเช่น แต่วัตถุชั้น ( ดูส่วนหนึ่งของเอกสารหลามนี้สำหรับสิ่งที่เป็น "ชั้นวัตถุ" เป็น) clsซึ่งโดยการประชุมที่เรียกว่า นี้จะดำเนินการกับมัณฑนากร @classmethod

การใช้งานทั่วไปของคำว่า "วิธีการแบบคงที่" ใน C / C ++ / etc ใช้กับทั้งวิธีการ "ระดับ" แบบคงที่และแบบ "งูใหญ่" ของ Python เนื่องจากวิธีทั้งสองประเภทนี้ไม่มีการอ้างอิงถึงอินสแตนซ์ ใน C / C ++ / etc โดยปกติเมธอดจะมีสิทธิ์เข้าถึงสมาชิก / วิธีที่ไม่ใช่อินสแตนซ์ทั้งหมดของคลาสซึ่งอาจเป็นสาเหตุที่ความแตกต่างนี้มีเฉพาะในภาษาเช่น Python / Ruby / etc


วิธีสแตติกใน C / C ++ มีการอ้างอิงถึงคลาสอ็อบเจ็กต์หรือไม่? หรือเพียงแค่ "สมาชิก" ของชั้นเรียน? พวกเขาสามารถสร้างสมาชิกใหม่ของชั้นเรียนได้หรือไม่ :)
Aaron Hall

3
@AaronHall ใน C / C ++ ไม่มีสิ่งนั้นเป็นวัตถุคลาสและคุณไม่จำเป็นต้องอ้างอิงเพื่อเรียกวิธีการคงที่ คุณเพิ่งเขียนClass::staticMethod()และแค่นั้นแหละ (ตราบใดที่คุณไม่ถูกห้ามไม่ให้เรียกมันเพราะstaticMethod()เป็นเรื่องส่วนตัวหรืออะไรบางอย่าง)
Ixrec
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.