ฉันต้องการทราบความแตกต่างระหว่าง__init__
และ__call__
วิธีการ
ตัวอย่างเช่น:
class test:
def __init__(self):
self.a = 10
def __call__(self):
b = 20
ฉันต้องการทราบความแตกต่างระหว่าง__init__
และ__call__
วิธีการ
ตัวอย่างเช่น:
class test:
def __init__(self):
self.a = 10
def __call__(self):
b = 20
คำตอบ:
ตัวแรกใช้เพื่อเริ่มต้นวัตถุที่สร้างขึ้นใหม่และรับอาร์กิวเมนต์ที่ใช้ในการทำเช่นนั้น:
class Foo:
def __init__(self, a, b, c):
# ...
x = Foo(1, 2, 3) # __init__
ตัวที่สองใช้ตัวดำเนินการเรียกฟังก์ชัน
class Foo:
def __call__(self, a, b, c):
# ...
x = Foo()
x(1, 2, 3) # __call__
__call__
คืออะไร?
การกำหนด__call__()
วิธีการที่กำหนดเองใน meta-class ทำให้อินสแตนซ์ของคลาสนั้นถูกเรียกว่าเป็นฟังก์ชั่น แต่ไม่ได้ปรับเปลี่ยนอินสแตนซ์ของตัวเองเสมอไป
In [1]: class A:
...: def __init__(self):
...: print "init"
...:
...: def __call__(self):
...: print "call"
...:
...:
In [2]: a = A()
init
In [3]: a()
call
__call__
ไม่เพียง แต่อนุญาตให้อินสแตนซ์ที่จะใช้เป็นฟังก์ชั่น ... มันกำหนดร่างกายฟังก์ชั่นที่ดำเนินการเมื่อมีการใช้อินสแตนซ์เป็นฟังก์ชั่น
ใน Python ฟังก์ชั่นเป็นวัตถุชั้นหนึ่งซึ่งหมายความว่า: การอ้างอิงฟังก์ชันสามารถส่งผ่านในอินพุตไปยังฟังก์ชันและ / หรือวิธีการอื่น ๆ และดำเนินการจากภายใน
อินสแตนซ์ของคลาส (วัตถุที่รู้จัก) สามารถปฏิบัติเหมือนกับว่าเป็นฟังก์ชัน: ส่งผ่านไปยังเมธอด / ฟังก์ชันอื่นและเรียกพวกมัน เพื่อให้บรรลุสิ่งนี้__call__
ฟังก์ชันคลาสจะต้องมีความเชี่ยวชาญ
def __call__(self, [args ...])
มันจะใช้เป็นอินพุตจำนวนตัวแปรของการขัดแย้ง สมมติว่าx
เป็นตัวอย่างของชั้นX
, x.__call__(1, 2)
จะคล้ายคลึงกับการเรียกร้องx(1,2)
หรืออินสแตนซ์ตัวเองเป็นฟังก์ชั่น
ใน Python __init__()
มีการกำหนด Class Constructor อย่างเหมาะสม (เช่นเดียวกับ__del__()
Class Destructor) ดังนั้นจึงมีความแตกต่างสุทธิระหว่าง__init__()
และ__call__()
: ครั้งแรกสร้างตัวอย่างของการเรียนขึ้นที่สองทำให้เช่นอินสแตนซ์callableเป็นฟังก์ชั่นจะไม่ส่งผลกระทบต่อวงจรชีวิตของวัตถุตัวเอง (เช่น__call__
ไม่ส่งผลกระทบต่อวงจรชีวิตการก่อสร้าง / ทำลาย) สามารถแก้ไขสถานะภายในของมันได้ (ดังแสดงด้านล่าง)
ตัวอย่าง.
class Stuff(object):
def __init__(self, x, y, range):
super(Stuff, self).__init__()
self.x = x
self.y = y
self.range = range
def __call__(self, x, y):
self.x = x
self.y = y
print '__call__ with (%d,%d)' % (self.x, self.y)
def __del__(self):
del self.x
del self.y
del self.range
>>> s = Stuff(1, 2, 3)
>>> s.x
1
>>> s(7, 8)
__call__ with (7,8)
>>> s.x
7
def __call__
ด้วยdef update
เราให้วิธีการในชั้นเรียนupdate
ที่ทำสิ่งเดียวกัน s.update(7, 8)
มันสามารถตอนนี้ยังปรับเปลี่ยนสถานะภายในถ้าเรียกว่าด้านล่าง งั้น__call__
น้ำตาลซินแทคติกก็แค่นั้นใช่ไหม
__call__
ทำให้อินสแตนซ์ของคลาส callable ทำไมมันจะต้อง?
ในทางเทคนิค__init__
จะถูกเรียกใช้ครั้งเดียว__new__
เมื่อวัตถุถูกสร้างขึ้นเพื่อให้สามารถเริ่มต้นได้
แต่มีหลายสถานการณ์ที่คุณอาจต้องการกำหนดวัตถุของคุณใหม่บอกว่าคุณทำกับวัตถุของคุณแล้วและอาจต้องหาวัตถุใหม่ ด้วย__call__
คุณสามารถกำหนดวัตถุเดียวกันเช่นถ้ามันเป็นของใหม่
นี่เป็นเพียงกรณีเดียวสามารถมีได้อีกมาก
>>> class A:
... def __init__(self):
... print "From init ... "
...
>>> a = A()
From init ...
>>> a()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: A instance has no __call__ method
>>>
>>> class B:
... def __init__(self):
... print "From init ... "
... def __call__(self):
... print "From call ... "
...
>>> b = B()
From init ...
>>> b()
From call ...
>>>
__init__
จะถือว่าเป็นตัวสร้างซึ่งเป็น__call__
วิธีการที่สามารถเรียกกับวัตถุจำนวนครั้งใด ๆ ทั้งสองฟังก์ชั่น__init__
และ__call__
ใช้อาร์กิวเมนต์เริ่มต้น
__init__
ไม่ใช่ฟังก์ชันตัวสร้าง แต่__new__
เป็น __init__
ถูกเรียกหลังจาก__new__
__new__
จะสร้างอินสแตนซ์ชั้นเรียนและได้รับชั้นเป็นอาร์กิวเมนต์ในขณะที่เป็นตัวสร้างอินสแตนซ์ซึ่งเป็นเหตุผลที่ได้รับ__init__
self
เป็นวิธีที่ง่ายที่จะเห็นนี้อยู่ในการเรียกฟังก์ชั่นที่จะได้รับข้อโต้แย้งที่สร้างจะเป็นa = Foo(1,2,3)
__init__
ฉันจะพยายามอธิบายเรื่องนี้โดยใช้ตัวอย่างสมมติว่าคุณต้องการพิมพ์คำศัพท์จำนวนคงที่จากชุดฟีโบนักชี โปรดจำไว้ว่า 2 คำแรกของชุดฟีโบนักชีคือ 1 วินาที เช่น 1, 1, 2, 3, 5, 8, 13 ....
คุณต้องการให้รายการที่มีหมายเลขฟีโบนักชีเริ่มต้นได้เพียงครั้งเดียวและหลังจากนั้นควรอัพเดท ตอนนี้เราสามารถใช้__call__
ฟังก์ชั่น อ่านคำตอบของ @mudit verma มันเหมือนกับว่าคุณต้องการให้วัตถุนั้นสามารถเรียกได้ว่าเป็นฟังก์ชั่น แต่ไม่ได้เริ่มต้นใหม่ทุกครั้งที่คุณเรียกมัน
เช่น:
class Recorder:
def __init__(self):
self._weights = []
for i in range(0, 2):
self._weights.append(1)
print self._weights[-1]
print self._weights[-2]
print "no. above is from __init__"
def __call__(self, t):
self._weights = [self._weights[-1], self._weights[-1] + self._weights[-2]]
print self._weights[-1]
print "no. above is from __call__"
weight_recorder = Recorder()
for i in range(0, 10):
weight_recorder(i)
ผลลัพธ์คือ:
1
1
no. above is from __init__
2
no. above is from __call__
3
no. above is from __call__
5
no. above is from __call__
8
no. above is from __call__
13
no. above is from __call__
21
no. above is from __call__
34
no. above is from __call__
55
no. above is from __call__
89
no. above is from __call__
144
no. above is from __call__
หากคุณสังเกตว่าเอาต์พุต__init__
ถูกเรียกเพียงครั้งเดียวนั่นคือเมื่อคลาสถูกสร้างอินสแตนซ์เป็นครั้งแรกในภายหลังบนวัตถุที่ถูกเรียกใช้โดยไม่ต้องเริ่มต้นใหม่
นอกจากนี้คุณยังสามารถใช้__call__
วิธีการในการสนับสนุนการดำเนินการตกแต่ง
ตัวอย่างนี้นำมาจากรูปแบบ Python 3 สูตรและสำนวน
class decorator_without_arguments(object):
def __init__(self, f):
"""
If there are no decorator arguments, the function
to be decorated is passed to the constructor.
"""
print("Inside __init__()")
self.f = f
def __call__(self, *args):
"""
The __call__ method is not called until the
decorated function is called.
"""
print("Inside __call__()")
self.f(*args)
print("After self.f( * args)")
@decorator_without_arguments
def sayHello(a1, a2, a3, a4):
print('sayHello arguments:', a1, a2, a3, a4)
print("After decoration")
print("Preparing to call sayHello()")
sayHello("say", "hello", "argument", "list")
print("After first sayHello() call")
sayHello("a", "different", "set of", "arguments")
print("After second sayHello() call")
ผลผลิต :
ดังนั้น__init__
ถูกเรียกเมื่อคุณสร้างอินสแตนซ์ของคลาสใด ๆ และเริ่มต้นตัวแปรอินสแตนซ์ด้วย
ตัวอย่าง:
class User:
def __init__(self,first_n,last_n,age):
self.first_n = first_n
self.last_n = last_n
self.age = age
user1 = User("Jhone","Wrick","40")
และ__call__
ถูกเรียกเมื่อคุณเรียกใช้ออบเจ็กต์เหมือนกับฟังก์ชันอื่น ๆ
ตัวอย่าง:
class USER:
def __call__(self,arg):
"todo here"
print(f"I am in __call__ with arg : {arg} ")
user1=USER()
user1("One") #calling the object user1 and that's gonna call __call__ dunder functions
__init__
เป็นวิธีพิเศษในคลาส Python มันเป็นวิธีการสร้างสำหรับชั้นเรียน มันถูกเรียกว่าเมื่อใดก็ตามที่วัตถุของชั้นเรียนถูกสร้างขึ้นหรือเราสามารถพูดได้ว่ามันเริ่มต้นวัตถุใหม่ ตัวอย่าง:
In [4]: class A:
...: def __init__(self, a):
...: print(a)
...:
...: a = A(10) # An argument is necessary
10
ถ้าเราใช้ A () ก็จะให้ข้อผิดพลาด
TypeError: __init__() missing 1 required positional argument: 'a'
ตามที่ต้องการ 1 โต้แย้งเพราะa
__init__
........
__call__
เมื่อมีการใช้งานใน Class ช่วยให้เราสามารถเรียกใช้อินสแตนซ์ของ Class เป็นฟังก์ชันการเรียกใช้
ตัวอย่าง:
In [6]: class B:
...: def __call__(self,b):
...: print(b)
...:
...: b = B() # Note we didn't pass any arguments here
...: b(20) # Argument passed when the object is called
...:
20
ที่นี่ถ้าเราใช้ B () มันทำงานได้ดีเพราะมันไม่มี__init__
ฟังก์ชั่นที่นี่
__call__
อนุญาตให้ส่งคืนค่าโดยพลการในขณะที่__init__
เป็นตัวสร้างส่งคืนอินสแตนซ์ของคลาสโดยปริยาย ดังที่คำตอบอื่น ๆ ถูกชี้อย่างชัดเจน__init__
ถูกเรียกเพียงครั้งเดียวในขณะที่สามารถโทรได้__call__
หลายครั้งในกรณีที่อินสแตนซ์เริ่มต้นถูกกำหนดให้กับตัวแปรกลาง
>>> class Test:
... def __init__(self):
... return 'Hello'
...
>>> Test()
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: __init__() should return None, not 'str'
>>> class Test2:
... def __call__(self):
... return 'Hello'
...
>>> Test2()()
'Hello'
>>>
>>> Test2()()
'Hello'
>>>
คำตอบสั้น ๆ และหวานจัดไว้แล้วข้างต้น ฉันต้องการให้มีการใช้งานจริงเมื่อเทียบกับ Java
class test(object):
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def __call__(self, a, b, c):
self.a = a
self.b = b
self.c = c
instance1 = test(1, 2, 3)
print(instance1.a) #prints 1
#scenario 1
#creating new instance instance1
#instance1 = test(13, 3, 4)
#print(instance1.a) #prints 13
#scenario 2
#modifying the already created instance **instance1**
instance1(13,3,4)
print(instance1.a)#prints 13
หมายเหตุ : สถานการณ์ 1 และสถานการณ์ 2 ดูเหมือนกันในแง่ของผลลัพธ์ผลลัพธ์ แต่ในสถานการณ์ 1 เราสร้างอินสแตนซ์ใหม่อีกอินสแตนซ์ 1 อีกครั้ง ในสถานการณ์ 2 เราเพียงแก้ไขอินสแตนซ์ที่สร้างไว้แล้ว1 __call__
มีประโยชน์ที่นี่เนื่องจากระบบไม่จำเป็นต้องสร้างอินสแตนซ์ใหม่
เทียบเท่าใน Java
public class Test {
public static void main(String[] args) {
Test.TestInnerClass testInnerClass = new Test(). new TestInnerClass(1, 2, 3);
System.out.println(testInnerClass.a);
//creating new instance **testInnerClass**
testInnerClass = new Test().new TestInnerClass(13, 3, 4);
System.out.println(testInnerClass.a);
//modifying already created instance **testInnerClass**
testInnerClass.a = 5;
testInnerClass.b = 14;
testInnerClass.c = 23;
//in python, above three lines is done by testInnerClass(5, 14, 23). For this, we must define __call__ method
}
class TestInnerClass /* non-static inner class */{
private int a, b,c;
TestInnerClass(int a, int b, int c) {
this.a = a;
this.b = b;
this.c = c;
}
}
}
เราสามารถใช้วิธีการโทรเพื่อใช้วิธีการเรียนอื่น ๆ เป็นวิธีการคงที่
class _Callable:
def __init__(self, anycallable):
self.__call__ = anycallable
class Model:
def get_instance(conn, table_name):
""" do something"""
get_instance = _Callable(get_instance)
provs_fac = Model.get_instance(connection, "users")
__init__
วิธีการที่จะใช้เมื่อชั้นถูกเรียกให้เริ่มต้นอินสแตนซ์ในขณะที่__call__
วิธีการที่เรียกว่าเมื่อมีการเรียกอินสแตนซ์