Python – การใช้งาน global, local, nonlocal

og:image

Python – การใช้งาน global, local, nonlocal

รู้จักกับ Global Variables

โดยทั่วไปแล้วตัวแปรที่ประกาศภายนอกฟังก์ชันหรือใน global scope จะเรียกตัวแปรนั้นว่าเป็น global variable และขอบเขตที่สามารถจะเรียกใช้ตัวแปรนี้ จะถูกเรียกดูข้อมูลได้ทั้งภายในและภายนอกฟังก์ชัน แต่จะสามารถแก้ไขตัวแปรนี้ได้ใน global scope เท่านั้นไม่สามารถทำการแก้ไขได้ภายในฟังก์ชันได้
ตัวอย่างการใช้งาน

# ฟังก์ชันสำหรับคำนวณเลขยกกำลัง
# ตัวอย่างเช่น 10^3 = 10 x 10 x 10
def calculate_power(power):
	total = 1
	for i in range(1, power+1):
		total *= base
	return total

# กำหนดค่าของฐานเป็น 10 ซึ่งตัวแปร base เป็น global variable
base = 10

# กำหนดเลขยกกำลังเป็น 5 เพื่อให้ฟังก์ชันทำการคำนวณ
result = calculate_power(5)

print("{} ยกกำลัง 5 มีค่าเป็น {}".format(base, result) )
# โปรแกรมทำการปรินต์ค่า
# 10 ยกกำลัง 5 มีค่าเป็น 100000


# เปลี่ยนค่าของฐานจากฐาน 10 เป็นฐาน 2 ซึ่งตัวแปร base เป็น global variable
base = 2

# กำหนดเลขยกกำลังเป็น 5 เพื่อให้ฟังก์ชันทำการคำนวณ
result = calculate_power(5)

print("{} ยกกำลัง 5 มีค่าเป็น {}".format(base, result) )
# โปรแกรมทำการปรินต์ค่า
# 2 ยกกำลัง 5 มีค่าเป็น 32

เราได้สร้างฟังก์ชันสำหรับการคำนวณเลขยกกำลัง โดยอาศัยข้อมูลว่า
2n = 2 x 2 x … x 2 เป็นจำนวน n ครั้ง
24 = 2 x 2 x 2 x 2 ตัวเลข 2 คูณกันเป็นจำนวน 4 ครั้ง

จากตัวอย่างได้ทำการประกาศตัวแปร base สำหรับเก็บข้อมูลเลขฐานไว้ใน global scope ซึ่งจะทำให้ตัวแปรสามารถเรียกใช้ได้จากทั้งภายในและภายนอกฟังก์ชัน( global/local scope ) แต่ไม่สามารถทำการแก้ไขข้อมูลได้ ทำให้ภายในฟังก์ชันเพื่อทำการคำนวณเลขยกกำลัง แม้จะไม่มีการประกาศตัวแปรสำหรับเก็บข้อมูลเลขฐานก็สามารถเรียกใช้ตัวแปรที่เก็บข้อมูลดังกล่าวได้

รู้จักกับ Local Variables

ตัวแปรที่ประกาศภายในฟังก์ชันหรือใน local scope จะเรียกว่า local variable และขอบเขตที่สามารถจะเรียกใช้ตัวแปรนี้ จะถูกเรียกใช้และแก้ไขได้เฉพาะภายในฟังก์ชันเท่านั้น หากทำการเรียกใช้ภายนอกฟังก์ชัน จะเกิดข้อผิดพลาดเนื่องจากไม่มีข้อมูลของตัวแปรนี้อยู่
ตัวอย่างการใช้งาน

# ฟังก์ชันสำหรับคำนวณเลขยกกำลัง
# ตัวอย่างเช่น 2^3 = 2 x 2 x 2
def calculate_power_of_two(power):

	# กำหนดตัวแปร base ซึ่งเป็น local variable เพื่อทำการเก็บค่าข้อมูลของเลขฐาน
	base = 2

	# กำหนดตัวแปร total ซึ่งเป็น local variable สามารถเรียกใช้งานได้ภายในฟังก์ชันเท่านั้น
	total = 1
	for i in range(1, power+1):
		total *= base
	return total

# กำหนดเลขยกกำลังเป็น 5 เพื่อให้ฟังก์ชันทำการคำนวณ
result = calculate_power_of_two(3)

print("{} ยกกำลัง 3 มีค่าเป็น {}".format(base, result) )
# โปรแกรมทำการปรินต์ค่า
# โปรแกรมเกิดข้อผิดพลาด NameError: name 'base' is not defined

จากตัวอย่าง ทำการกำหนดตัวแปร base ซึ่งเป็น local variable ไว้ภายในฟังก์ชัน จึงสามารถเรียกใช้งานได้เพียงภายในฟังก์ชันนั้นเท่านั้น เมื่อทำการเรียกใช้ค่าดังกล่าวภายนอกฟังก์ชัน(global scope) ทำให้เกิดข้อผิดพลาดเพราะไม่มีข้อมูลตัวแปรดังกล่าว

การทำงานของ Global/Local variables เมื่อใช้งานตัวแปรชื่อเดียวกัน

เมื่อในโปรแกรมมีการกำหนดตัวแปรชื่อเดียวกันที่อยู่ต่าง scope กันเช่น ตัวแปร “x” สร้างจากภายนอกฟังก์ชัน(global scope) และถูกสร้างในฟังก์ชัน(local scope) ด้วยตัวแปรชื่อเดียวกัน ในบางกรณีนั้นตัวประมวลผลจะมองตัวแปรนี้เป็นตัวแปร 2 ตัวที่ต่าง scope กันและถูกจัดเป็นตัวแปรคนละตัวที่ถูกเก็บอยู่ในหน่วยความจำที่ต่างกัน
ตัวอย่างการใช้งาน

# กำหนดตัวแปร total ไว้ใน(global scope)
total = 1

# ฟังก์ชันสำหรับคำนวณเลขยกกำลัง
# ตัวอย่างเช่น 2^6 = 2 x  2 x 2 x 2 x 2 x 2
def calculate_power(base, power):
	# กำหนดตัวแปร total ไว้ใน(local scope)
	total = 1
	for i in range(1, power+1):
		total *= base
	return total

# กำหนดค่าให้ตัวแปรของเลขฐานเป็น 10 และเลขชี้กำลังเป็น 6
base = 2
power = 6

# ทำการคำนวณเลขยกกำลัง โดยการส่งข้อมูลเลขฐาน และเลขชี้กำลัง
result = calculate_power(base, power)

# ทำการปรินต์ค่าผลการคำนวณจากการคืนค่าออกมาจากฟังก์ชัน
print("{} ยกกำลัง {} มีค่าเป็น {}".format(base, power, result) )
# โปรแกรมทำการปรินต์ค่า
# 2 ยกกำลัง 6 มีค่าเป็น 64

# ทำการปรินต์ค่าผลการคำนวณจากตัวแปร total ซึ่งเป็นตัวแปรที่ถูกประกาศไว้ใน global scope และในฟังก์ชันตัวแปรชื่อเดียวกันก็ใช้ในการเก็บผลการคำนวณเลขยกกำลัง แ
print("{} ยกกำลัง {} มีค่าเป็น {}".format(base, power, total) )
# โปรแกรมทำการปรินต์ค่า
# 2 ยกกำลัง 6 มีค่าเป็น 1

จากตัวอย่าง มีการประกาศตัวแปร total ไว้ใน global scope ซึ่งไว้เก็บผลการคำนวณ และประกาศตัวแปร total ไว้ภายในฟังก์ชันเพื่อทำการเก็บผลการคำนวณเช่นกัน โดยใช้ชื่อตัวแปรเดียวกันทั้งภายใน(local scope)และภายนอกฟังก์ชัน(global scope) เมื่อมีการทำการคำนวณและเปลี่ยนแปลงข้อมูลภายในฟังก์ชันนั้น เราจะไม่สามารถแก้ไขข้อมูลที่เป็น global scope ได้ ดังนั้นตัวแปรที่อยู่ภายใน local scope จะถูกเรียกใช้และแก้ไขข้อมูลแทน โดยเมื่อออกจากฟังก์ชันแล้วตัวแปรที่อยู่ภายใน global scope จะถูกเรียกใช้แทน

ดังนั้นถึงแม้ตัวแปรทั้งสองตัวที่อยู่คนละ scope จะมีชื่อเดียวกัน ตัวประมวลผลก็จัดเป็นตัวแปรสองตัวนี้ให้เป็นตัวแปรคนละตัวกันและถูกเก็บอยู่ในหน่วยความจำในตำแหน่งที่ต่างกัน ดังนั้นเมื่อทำการเรียกดูข้อมูลจากตัวแปร total ใน global scope อีกครั้งหนึ่งค่าข้อมูลดังกล่าวจะไม่มีการเปลี่ยนแปลงจะยังคงค่าเดิมก่อนทำการเรียกใช้ฟังก์ชัน ทำให้ หากมีการปรินต์ค่าจากตัวแปรดังกล่าวนั้นไม่ถูกต้อง

การใช้งานคีย์เวิร์ด global

เราจะใช้งานคีย์เวิร์ด global เมื่อต้องการจะกำหนดให้ตัวแปรที่ถูกประกาศภายในฟังก์ชัน(local scope) ให้กลายเป็นตัวแปรที่สามารถใช้งานได้ใน global scope ได้เช่นกัน
ตัวอย่างการใช้งาน

# ฟังก์ชันสำหรับคำนวณเลขยกกำลัง
# ตัวอย่างเช่น 2^3 = 2 x 2 x 2
def calculate_power(power):

	# กำหนดตัวแปร total ซึ่งเป็น local variable ด้วยคีย์เวิร์ด global เพื่อจะทำให้ตัวแปรนี้ใช้งานใน global scope ได้ด้วย
	global total
	total = 1
	for i in range(1, power+1):
		total *= base

# กำหนดค่าของฐานเป็น 10 
base = 2

# กำหนดเลขยกกำลังเป็น 5 เพื่อให้ฟังก์ชันทำการคำนวณ
calculate_power(3)
print("2 ยกกำลัง 3 มีค่าเป็น {}".format(total) )
# โปรแกรมทำการปรินต์ค่า
# 2 ยกกำลัง 3 มีค่าเป็น 8

จากตัวอย่างโปรแกรมข้างต้น เราได้ทำการประกาศตัวแปร “total” ไว้ในฟังก์ชัน(local scope) ซึ่งโดยปกติแล้วจะถูกเรียกใช้ได้ภายในฟังก์ชันเท่านั้น แต่เราทำการกำกับตัวแปรดังกล่าวด้วยคีย์เวิร์ด global ซึ่งจะทำให้ตัวแปรดังกล่าวสามารถูกเรียกใช้งานจากภายนอกฟังก์ชันได้ด้วย(global scope) ซึ่งจะทำให้เราสามารถเรียกใช้ผลของการคำนวณหาเลขยกกำลัง ที่ถูกคำนวณได้จากภายในฟังก์ชันได้ภายนอกฟังก์ชันได้ทันที่ โดยไม่จำเป็นต้องมีการใช้คีย์เวิร์ด return เพื่อระบุการคืนค่าข้อมูลออกมาภายนอกฟังก์ชัน

การใช้งานคีย์เวิร์ด nonlocal

การใช้งาน non-local variable มักจะถูกใช้ใน nested ฟังก์ชันซึ่งจะไม่มี local scope โดยตัวแปรนั้นไม่สามารถเป็นได้ทั้ง local scope และ global scope
ตัวอย่างการใช้งาน

# กำหนดฟังก์ชันสำหรับการคำนวณการ modulo
def calculate_remainder(number, divided_by):

	# กำหนดตัวแปร quotient สำหรับเก็บข้อมูลผลลัพท์(ซึ่งเป็นจำนวนเต็ม) ที่ได้จากการหารจำนวนเต็ม ด้วยตัวหาร
	quotient = 0

	# กำหนดตัวแปร remainder สำหรับเก็บเศษ จากการหารจำนวนเต็ม ด้วยตัวหารแล้วได้ผลลัพท์เป็นจำนวนเต็มบวก
	remainder = number

	# กำหนด nested ฟังก์ชันอยู่ภายในฟังก์ชัน ซึ่งจะทำการลดค่าของข้อมูลลงตามตัวลบที่กำหนด
	def subtract_value(number, subtract_by):

		# กำหนดตัวแปรกำกับด้วยคีย์เวิร์ด nonlocal เพื่อจะทำให้ตัวแปรดังกล่าวสามารถูกเรียกใช้ได้จากภายในฟังก์ชันได้ด้วย
		nonlocal quotient

		number = number-subtract_by
		quotient += 1

		return number
	
	while(remainder>=divided_by):
		remainder = subtract_value(remainder, divided_by)

	return quotient, remainder

number = 100
divided_by = 3
quotient, remainder = calculate_remainder(number, divided_by)
print("{} = ({}x{}) + {}".format(number, quotient, divided_by, remainder))
print("100 % 3 = {}".format(remainder))

# โปรแกรมทำการปรินต์ค่า
# 100 = (33 x 3) + 1
# 100 % 3 = 1

จากตัวอย่างข้างต้น เราทำการสร้างฟังก์ชันชื่เพื่อทำการคำนวณหา modulo เพื่อหาข้อมูลผลลัพท์(ซึ่งเป็นจำนวนเต็ม) ที่ได้จากการหารจำนวนเต็ม(number) ด้วยตัวหาร(divisor)
โดยวิธีการการคำนวณ modulo นั้นจะเป็นไปตามสมการ

number = (quotient x divisor) + remainder
โดย 0 <= remainder < |divisor|

ซึ่งใช้หลักการว่าจำนวนเต็มจำนวนหนึ่ง(number) นั้นเกิดจากการนำจำนวนเต็มจำนวนหนึ่ง(quotient) ไปคูณกับจำนวนเต็มอีกจำนวนหนึ่ง(remainder) แล้วบวกด้วยเศษ จะได้เป็นจำนวนเต็มนั้น

โดยภายในฟังก์ชันนั้นจะมี nested ฟังก์ชันชื่อ “subtract_value” ที่ไว้ทำการลดค่าของจำนวนลงเรื่อยๆ จนมีค่าน้อยกว่าค่าของตัวหารที่กำหนด โดยใน nested ฟังก์ชันนั้น เราทำการกำกับตัวแปรด้วยคีย์เวิร์ด “nonlocal” ให้กับตัวแปร quotient เพื่อทำให้เมื่อเราทำการเปลี่ยนแปลงข้อมูลกับตัวแปร quotient ภายใน nested ฟังก์ชันแล้ว ข้อมูลดังกล่าวจะถูกทำการเปลี่ยนแปลงให้กับตัวแปร quotient ที่อยู่ในฟังก์ชัน “calculate_remainder” ซึ่งเป็น local variable ด้วยเช่นกัน