วิธีคืนค่าจาก __init__ ใน Python


105

ฉันมีคลาสที่มี__init__ฟังก์ชัน

ฉันจะคืนค่าจำนวนเต็มจากฟังก์ชันนี้เมื่อสร้างวัตถุได้อย่างไร

ฉันเขียนโปรแกรมโดยที่__init__จะแยกวิเคราะห์บรรทัดคำสั่งและฉันต้องตั้งค่าบางอย่าง ตกลงตั้งค่าเป็นตัวแปรส่วนกลางและใช้ในฟังก์ชันสมาชิกอื่น ๆ หรือไม่ ถ้าเป็นเช่นนั้นจะทำอย่างไร? จนถึงตอนนี้ฉันได้ประกาศตัวแปรนอกคลาส และการตั้งค่าให้ฟังก์ชันหนึ่งไม่สะท้อนในฟังก์ชันอื่น ??


8
หากคุณกำลังพิจารณาส่งคืนรหัสข้อผิดพลาดให้เพิ่มข้อยกเว้นแทน
JoeG

1
โปรดลบความคิดเห็นของคุณและอัปเดตคำถามของคุณ คุณเป็นเจ้าของคำถาม มันเป็นคำถามของคุณ โปรดแก้ไขคำถามเพื่อแสดงให้ถูกต้องว่าปัญหาที่แท้จริงของคุณคืออะไร คุณกำลัง misusing __init__; เราสามารถช่วยคุณได้หากคุณอธิบายถึงสิ่งที่คุณพยายามทำให้สำเร็จ
ล็อต

คำตอบ:


120

__init__จำเป็นต้องส่งคืน None คุณไม่สามารถ (หรืออย่างน้อยก็ไม่ควร) ส่งคืนอย่างอื่น

ลองทำสิ่งที่คุณต้องการส่งคืนตัวแปรอินสแตนซ์ (หรือฟังก์ชัน)

>>> class Foo:
...     def __init__(self):
...         return 42
... 
>>> foo = Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() should return None

24
+1: คุณไม่สามารถคืนสิ่งอื่นได้ มันไม่สมเหตุสมผลเลย
ล็อต

73
initไม่ส่งคืนอ็อบเจ็กต์ที่สร้างขึ้นใหม่ - ดังที่เห็นใน TypeError จำเป็นต้องส่งคืน None ใช่ไหม อ็อบเจ็กต์ที่สร้างขึ้นใหม่จะถูกส่งคืนโดยnew , initเพียงแค่ตั้งค่าคุณสมบัติบางอย่าง แต่ใช่อย่างที่คุณบอกการเปลี่ยนinitหรือใหม่เพื่อส่งคืนอย่างอื่นไม่สมเหตุสมผลเลย
weronika

ที่newนี่ที่ไหน? เป็นnewนัยใน Python หรือไม่? ฉันคิดว่าความหมายของ Python แตกต่างจาก Java และภาษาอื่น ๆ ที่ใช้คำนี้
cs95

1
@Shiva AFAIK โดย new weronika หมายถึง __new __ (ตัวเอง) ไม่ใช่ java semantic ทั่วไป
Harsh Daftary

2
เพียงเพราะมันทำไม่ได้ไม่ได้หมายความว่ามันไม่สมเหตุสมผล ตัวอย่างเช่นจะเป็นการดีที่จะส่งผ่านข้อมูลจากsuper().__init__ไปยังคลาสที่ได้รับโดยไม่ต้องถ่ายทอดผ่านตัวแปรอินสแตนซ์
cz

125

ทำไมคุณถึงอยากทำเช่นนั้น?

หากคุณต้องการส่งคืนวัตถุอื่นเมื่อมีการเรียกคลาสให้ใช้__new__()วิธีการ:

class MyClass(object):
    def __init__(self):
        print "never called in this case"
    def __new__(cls):
        return 42

obj = MyClass()
print obj

9
ใช่ใหม่เป็นวิธีที่ถูกต้องในการส่งคืนสิ่งอื่นที่ไม่ใช่อินสแตนซ์คลาสเมื่อใช้คลาส ... ฉันแค่สงสัย - มีเหตุผลอะไรที่คุณอาจต้องการทำเช่นนั้นจริงหรือ?
weronika

34
@weronika หนึ่งความคิด: ในทุกสถานการณ์ที่ปกติคุณใช้โรงงาน แต่คุณมีเหตุผลบางอย่างที่ต้องการนำเสนออินเทอร์เฟซที่ดูเหมือนการสร้างอินสแตนซ์คลาสปกติ ตัวอย่าง: เมื่อเพิ่มพารามิเตอร์ทางเลือกใหม่ลงในคลาสของ__init__คุณคุณจะรู้ว่าจริงๆแล้วเพื่อให้มีความยืดหยุ่นที่คุณต้องการคุณต้องมีโรงงานคลาสที่ส่งคืนอินสแตนซ์ของคลาสย่อยเฉพาะ แต่ผู้ใช้ห้องสมุดของคุณใช้ API ที่มีอยู่แล้ว เพื่อรักษาไว้คุณจะแทนที่__new__เพื่อส่งคืนอินสแตนซ์ของคลาสย่อยเฉพาะของคุณ
Mark Amery

10
หากคุณต้องการดูตัวอย่างสิ่งที่ Mark Amery กล่าวให้ตรวจสอบซอร์สโค้ดของdatetimeโมดูลจาก Standard Library มันใช้__new__ในรูปแบบนี้
Zearin

นอกจากนี้หากใครต้องการทำเช่นนี้อย่าลืมสืบทอดจากวัตถุมิฉะนั้นจะไม่ได้ผล
Mino_e

ฉันคิดว่าในส่วนนี้แค่ใช้ฟังก์ชันปกติก็เข้าท่ากว่า อาจเป็นคนแปลกหน้าสำหรับคนจากมิติ Java (ฟังก์ชั่นไม่ได้อยู่ในคลาส? นอกรีต!) (นอกจากนี้คุณสามารถกำหนดคุณสมบัติให้กับฟังก์ชั่นได้เช่นเดียวกับใน funtionName.val = .. ซึ่งเป็นแบบป่า แต่ใช้งานได้)
Shayne

37

จากเอกสารของ__init__ :

เนื่องจากข้อ จำกัด พิเศษเกี่ยวกับตัวสร้างจึงไม่สามารถส่งคืนค่าได้ การทำเช่นนี้จะทำให้เกิด TypeError ขึ้นในขณะรันไทม์

เพื่อเป็นหลักฐานรหัสนี้:

class Foo(object):
    def __init__(self):
        return 2

f = Foo()

ให้ข้อผิดพลาดนี้:

Traceback (most recent call last):
  File "test_init.py", line 5, in <module>
    f = Foo()
TypeError: __init__() should return None, not 'int'

17

ตัวอย่างการใช้เรื่องที่เป็นปัญหาอาจเป็นดังนี้:

class SampleObject(object):

    def __new__(cls, item):
        if cls.IsValid(item):
            return super(SampleObject, cls).__new__(cls)
        else:
            return None

    def __init__(self, item):
        self.InitData(item) #large amount of data and very complex calculations

...

ValidObjects = []
for i in data:
    item = SampleObject(i)
    if item:             # in case the i data is valid for the sample object
        ValidObjects.append(item)

ฉันไม่มีชื่อเสียงมากพอเลยเขียนคอมเมนต์ไม่ได้มันบ้ามาก! ฉันหวังว่าฉันจะโพสต์เป็นความคิดเห็นถึงweronika


3
สิ่งนี้จะเพิ่ม NameError: selfไม่ได้กำหนดไว้ใน__new__(cls, Item)
Hart Simha

15

__init__วิธีเช่นวิธีการและผลตอบแทนที่ฟังก์ชั่นอื่น ๆ ไม่มีโดยเริ่มต้นในกรณีที่ไม่มีคำสั่งกลับเพื่อให้คุณสามารถเขียนมันชอบอย่างใดอย่างหนึ่งต่อไปนี้:

class Foo:
    def __init__(self):
        self.value=42

class Bar:
    def __init__(self):
        self.value=42
        return None

แต่แน่นอนว่าการเพิ่มreturn Noneไม่ได้ซื้ออะไรให้คุณ

ฉันไม่แน่ใจว่าคุณเป็นอย่างไร แต่คุณอาจสนใจสิ่งใดสิ่งหนึ่งต่อไปนี้:

class Foo:
    def __init__(self):
        self.value=42
    def __str__(self):
        return str(self.value)

f=Foo()
print f.value
print f

พิมพ์:

42
42

โอ้.. ฉันสามารถเข้าถึงตัวแปรสมาชิกจากคลาสได้หรือไม่? นั่นน่าจะช่วยแก้ปัญหาของฉันได้ .... ขอบคุณ
webminal.org

@lakshmipathi ใช่ตัวแปรอินสแตนซ์เช่นนี้เป็นแบบสาธารณะ
quamrana

ในฐานะผู้ดำเนินการเพื่อรับสิ่งที่มีค่ากลับมาหลังจากเริ่มคลาส:f = Foo().value
JLT

@JLT ใช่คุณลูกเบี้ยวเสมอทำอย่างนั้น __init__แต่ก็ยังไม่ได้หมายความว่าสิ่งที่ถูกส่งกลับจาก
quamrana


4

คุณสามารถตั้งค่าเป็นตัวแปรคลาสและอ่านได้จากโปรแกรมหลัก:

class Foo:
    def __init__(self):
        #Do your stuff here
        self.returncode = 42
bar = Foo()
baz = bar.returncode

3

init () ไม่ส่งคืนค่าที่แก้ไขได้อย่างสมบูรณ์

class Solve:
def __init__(self,w,d):
    self.value=w
    self.unit=d
def __str__(self):
    return str("my speed is "+str(self.value)+" "+str(self.unit))
ob=Solve(21,'kmh')
print (ob)

เอาต์พุต: ความเร็วของฉันคือ 21 กม


2

เพียงต้องการเพิ่มคุณสามารถส่งคืนชั้นเรียนใน __init__

@property
def failureException(self):
    class MyCustomException(AssertionError):
        def __init__(self_, *args, **kwargs):
            *** Your code here ***
            return super().__init__(*args, **kwargs)

    MyCustomException.__name__ = AssertionError.__name__
    return MyCustomException

วิธีการข้างต้นช่วยให้คุณดำเนินการเฉพาะกับข้อยกเว้นในการทดสอบของคุณ


2
super().__init__กำลังจะกลับมาNoneดังนั้นคุณกำลังจะกลับมาNoneซึ่งก็ดี แต่ซ้ำซ้อน
cz

-2

ถ้าคุณไม่สนใจอินสแตนซ์วัตถุอีกต่อไป ... คุณสามารถแทนที่ได้!

class MuaHaHa():
def __init__(self, ret):
    self=ret

print MuaHaHa('foo')=='foo'

2
เพียงแค่เปลี่ยนสิ่งที่กำหนดให้กับชื่อselfภายในตัวสร้างนั้น
Ondrej K.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.