🇯🇵 日本語 | 🇺🇸 English | 🇪🇸 Español | 🇵🇹 Português | 🇹🇭 ไทย | 🇨🇳 中文

NameError ใน Python ไม่น่ากลัว! คู่มือฉบับสมบูรณ์สำหรับข้อผิดพลาด "ตัวแปรไม่ได้ถูกกำหนด" สำหรับมือใหม่

ตอนที่เริ่มเรียนเขียนโปรแกรมใหม่ๆ ข้อความแสดงข้อผิดพลาดสีแดงที่ปรากฏขึ้นมา มันเหมือนกับกำลังบอกเราว่า "นายทำไม่ได้หรอก" จนทำให้ใจฝ่อได้เลยใช่ไหมครับ พูดตามตรง ตัวผมเองที่เมื่อไม่กี่เดือนก่อนยังไม่มีความรู้ด้านโปรแกรมมิ่งเลย ก็ต้องมานั่งจ้องหน้าจอข้อผิดพลาดทุกวันเหมือนกัน

โดยเฉพาะอย่างยิ่ง หนึ่งในกำแพงแรกที่มือใหม่ต้องเจอ ก็น่าจะเป็นข้อผิดพลาดที่ว่า `NameError: name '...' is not defined` นี่แหละครับ

แต่ไม่ต้องกังวลไปครับ ข้อผิดพลาดนี้ไม่ได้ยากอะไรเลย กลับกัน มันเป็นสัญญาณที่ Python กำลังบอกเราอย่างใจดีว่า "ขอโทษนะ ผมไม่รู้จักชื่อ '...' ที่คุณพูดถึง..."

ในบทความนี้ ผมที่สร้างเว็บไซต์ 2 แห่งได้ด้วยตัวเองในเวลาเดือนครึ่งโดยอาศัยความช่วยเหลือจาก AI จะมาอธิบายถึงตัวตนที่แท้จริงของ `NameError` และวิธีแก้ไข จาก "มุมมองของมือใหม่" เช่นเดียวกับทุกคนอย่างละเอียดถี่ถ้วนและเข้าใจง่ายกว่าที่ไหนๆ ครับ ผมจะไม่ใช้ศัพท์เทคนิค แต่จะใช้ตัวอย่างที่เป็นรูปธรรมที่ผมเคยเจอมาจริงๆ และรับรองได้เลยว่า เมื่อคุณอ่านบทความนี้จบ คุณจะสามารถแก้ไข `NameError` ได้ด้วยตัวเองอย่างแน่นอน

และที่สำคัญที่สุด ผมได้เตรียมโค้ดที่สามารถ "ทำงานได้!" เพียงแค่คัดลอกและวางไว้มากมาย เรามาค้นพบความสนุกของการเขียนโปรแกรมอีกครั้งผ่านความสุขในการแก้ไขข้อผิดพลาดด้วยกันเถอะครับ!


NameError คืออะไร? - สัญญาณจาก Python ที่บอกว่า "ฉันไม่รู้จักสิ่งนั้น!"

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

ตัวอย่างเช่น สมมติว่าคุณรันโค้ดต่อไปนี้


# พยายามแสดงข้อความทักทาย
print(message)
            

เมื่อรันโค้ดนี้ จะเกิดข้อผิดพลาดนี้ 100%


Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'message' is not defined
            

ถ้าแปลตรงตัว `NameError: name 'message' is not defined` ก็คือ "ข้อผิดพลาดเกี่ยวกับชื่อ: ชื่อ 'message' ยังไม่ได้ถูกกำหนด" หมายความว่า Python ได้รับคำสั่งให้แสดงผลสิ่งที่เรียกว่า `message` ด้วย `print()` แต่เนื่องจากไม่มีการเขียนบอกไว้ที่ไหนเลยว่า `message` คืออะไร (ยังไม่ได้ถูกกำหนด) มันจึงแสดงข้อผิดพลาดและหยุดการทำงาน

ข้อความแสดงข้อผิดพลาด (Traceback) เป็นคำใบ้สำคัญที่บอกเราว่าปัญหาเกิดขึ้นที่ไหน `File "<stdin>", line 1` หมายความว่า "เกิดข้อผิดพลาดที่บรรทัดที่ 1" เรามาใช้คำใบ้นี้เพื่อหาสาเหตุกันเถอะครับ


[แยกตามสาเหตุ] 3 กรณีคลาสสิกของ NameError และวิธีแก้ไข

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

กรณีที่ 1: พิมพ์ผิด (สะกดผิด)

นี่คือสาเหตุที่พบบ่อยที่สุด และอาจจะเป็นสาเหตุที่หายากที่สุดด้วยก็ได้ครับ ผมเองก็เคยมีประสบการณ์นั่งงงอยู่ 30 นาทีเพราะเขียน "`mesage`" แทนที่จะเป็น "`message`" ชื่อตัวแปรหรือฟังก์ชัน แม้จะต่างกันเพียงตัวอักษรเดียว Python ก็จะมองว่าเป็นคนละตัวกันโดยสิ้นเชิง

❌ ตัวอย่างที่ไม่ดี (ทำให้เกิด NameError)

เรากำหนดค่าตัวแปร `greeting` และพยายามจะแสดงผล แต่ดันพิมพ์ผิดเป็น `greting` ในคำสั่ง `print()`


# เก็บคำทักทายไว้ในตัวแปรชื่อ "greeting"
greeting = "สวัสดีชาวโลก!"

# พิมพ์ผิดตอนจะแสดงผล!
print(greting) # ← ขาด 'g' ไปหนึ่งตัว!
            

ผลลัพธ์ของข้อผิดพลาด:

NameError: name 'greting' is not defined

✅ ตัวอย่างที่ดี (ทำงานถูกต้อง)

แก้ไขที่พิมพ์ผิด และเรียกใช้ `print()` ด้วยชื่อเดียวกับชื่อตัวแปรที่กำหนดไว้ คือ `greeting` แค่นี้ข้อผิดพลาดก็จะหายไปราวกับเวทมนตร์


# เก็บคำทักทายไว้ในตัวแปรชื่อ "greeting"
greeting = "สวัสดีชาวโลก!"

# แสดงผลโดยใช้ชื่อตัวแปรที่ถูกต้อง
print(greeting)
            

ผลลัพธ์การทำงาน:

สวัสดีชาวโลก!

[เคล็ดลับการแก้ไข] เมื่อเจอ `NameError` ก่อนอื่นให้ลองเทียบชื่อที่แสดงในข้อความแสดงข้อผิดพลาด (`'greting'`) กับชื่อตัวแปรที่คุณตั้งใจจะกำหนด (`greeting`) ทีละตัวอักษร เพื่อตรวจสอบว่าพิมพ์ผิดหรือไม่


กรณีที่ 2: เรียกใช้ตัวแปรก่อนที่จะกำหนดค่า

โดยพื้นฐานแล้ว โปรแกรมจะทำงานตามลำดับจากบนลงล่าง นี่ก็เหมือนกับสูตรทำอาหารนั่นแหละครับ ถึงแม้ในสูตรจะบอกว่า "โรยเกลือ" เป็นขั้นตอนแรก แต่ถ้ายังไม่มีขั้นตอน "เตรียมเนื้อไก่" อยู่ก่อนหน้า ก็จะไม่รู้ว่าจะโรยเกลือใส่อะไรใช่ไหมครับ Python ก็เช่นกัน ถ้าพยายามใช้ตัวแปรก่อนที่จะกำหนดค่าให้ (ประกาศตัวแปร) ก็จะเกิด `NameError`

❌ ตัวอย่างที่ไม่ดี (ทำให้เกิด NameError)

เราพยายามจะแสดงผลชื่อผู้ใช้ `user_name` แต่บรรทัดที่กำหนดชื่อให้กับ `user_name` จริงๆ กลับอยู่ถัดไป


# พยายามแสดงผลทั้งๆที่ยังไม่รู้ว่าข้างในมีอะไร
print(user_name)

# กำหนดค่าให้ตัวแปรหลังจากที่พยายามแสดงผลไปแล้ว
user_name = "สมชาย"
            

ผลลัพธ์ของข้อผิดพลาด:

NameError: name 'user_name' is not defined

✅ ตัวอย่างที่ดี (ทำงานถูกต้อง)

แก้ไขลำดับการทำงานให้ถูกต้อง ก่อนอื่น กำหนดสตริง "สมชาย" ให้กับ `user_name` (ประกาศตัวแปร) แล้วหลังจากนั้นค่อยเรียกใช้ `print()`


# กำหนดค่าให้ตัวแปร (ประกาศตัวแปร) ก่อน
user_name = "สมชาย"

# หลังจากกำหนดค่าแล้ว ค่อยแสดงผลตัวแปร
print(user_name)
            

ผลลัพธ์การทำงาน:

สมชาย

[เคล็ดลับการแก้ไข] หากเจอ `NameError` ให้ตรวจสอบดูว่าตัวแปรนั้นถูกกำหนดค่าอย่างถูกต้องในบรรทัดที่อยู่สูงกว่าบรรทัดที่เกิดข้อผิดพลาดหรือไม่ การไล่ดูการทำงานของโปรแกรมจากบนลงล่างด้วยนิ้วก็เป็นวิธีที่มีประสิทธิภาพครับ


กรณีที่ 3: กำแพง "Scope" - เรียกใช้ตัวแปรนอกขอบเขตที่ใช้งานได้

นี่เป็นเรื่องที่ประยุกต์ขึ้นมาเล็กน้อย แต่ก็เป็นกับดักขนาดใหญ่ที่มือใหม่มักจะตกลงไป "Scope" ถ้าพูดง่ายๆ ก็คือ "ขอบเขตที่ตัวแปรสามารถใช้งานได้" ครับ ผมมักจะเรียกมันว่า "ห้องของตัวแปร"

ตัวแปรที่ถูกกำหนดขึ้นภายในฟังก์ชัน (Local variable) จะสามารถใช้ได้เฉพาะภายในห้องของฟังก์ชันนั้นๆ เท่านั้น หากพยายามเรียกใช้ตัวแปรนั้นจากนอกฟังก์ชัน Python จะตอบกลับมาด้วย `NameError` ว่า "ไม่มีตัวแปรชื่อนั้นอยู่ในห้องนี้ (Global scope) นะ"

❌ ตัวอย่างที่ไม่ดี (ทำให้เกิด NameError)

ในฟังก์ชัน `create_message` มีการกำหนดตัวแปร `local_msg` ซึ่งเป็นตัวแปรที่ใช้ได้เฉพาะในห้องของ `create_message` เท่านั้น แต่เรากลับพยายามเรียกใช้มันจากนอกฟังก์ชัน (นอกห้อง) ด้วย `print(local_msg)` จึงทำให้เกิดข้อผิดพลาด


def create_message():
    # ตัวแปรนี้ใช้ได้เฉพาะใน "ห้อง" ของฟังก์ชัน create_message() เท่านั้น
    local_msg = "นี่คือข้อความท้องถิ่น"
    print("มองเห็นจากข้างในฟังก์ชัน:", local_msg)

# เรียกใช้งานฟังก์ชัน
create_message()

# พยายามเรียกใช้ตัวแปรจากนอก "ห้อง" ของฟังก์ชัน
print(local_msg) # ← เกิดข้อผิดพลาดตรงนี้!
            

ผลลัพธ์ของข้อผิดพลาด:

มองเห็นจากข้างในฟังก์ชัน: นี่คือข้อความท้องถิ่น
Traceback (most recent call last):
  File "<stdin>", line 9, in <module>
NameError: name 'local_msg' is not defined

จะเห็นว่า `print` ครั้งแรกทำงานสำเร็จ แต่เกิดข้อผิดพลาดที่บรรทัดที่ 9


✅ ตัวอย่างที่ดี (ทำงานถูกต้อง)

หากต้องการใช้ค่าที่อยู่ในห้องของฟังก์ชันจากภายนอก จำเป็นต้องใช้ `return` เพื่อส่งค่าออกไปเป็น "ค่าที่ส่งกลับ" (return value) ของฟังก์ชัน ลองนึกภาพว่าฟังก์ชันส่งค่ากลับมา แล้วเราก็ใช้ตัวแปรใหม่มารับค่านั้นไว้


def create_message():
    # ตัวแปรนี้ใช้ได้เฉพาะใน "ห้อง" ของฟังก์ชัน create_message() เท่านั้น
    local_msg = "นี่คือข้อความที่จะส่งออกไปข้างนอก"
    # ใช้ return เพื่อส่ง "ค่า" ของตัวแปรออกไปนอกฟังก์ชัน
    return local_msg

# เรียกใช้งานฟังก์ชัน และรับค่าที่ส่งกลับมาด้วยตัวแปรชื่อ message_from_func
message_from_func = create_message()

# แสดงผลตัวแปรที่ได้รับมา
print(message_from_func)
            

ผลลัพธ์การทำงาน:

นี่คือข้อความที่จะส่งออกไปข้างนอก

[เคล็ดลับการแก้ไข] กรณีที่ต้องการใช้ค่าที่สร้างขึ้นภายในฟังก์ชันจากภายนอก การใช้ `return` เพื่อส่งผลลัพธ์กลับมาเป็นพื้นฐานครับ หากจำเป็นต้องแก้ไขตัวแปรที่อยู่ภายนอกฟังก์ชันจากภายในจริงๆ ก็มีวิธีที่ใช้คีย์เวิร์ด `global` อยู่ แต่เนื่องจากจะทำให้โปรแกรมซับซ้อนขึ้น จึงแนะนำให้ฝึกใช้ `return` ให้คล่องก่อนจะดีกว่าครับ ในประเด็นนี้ เว็บไซต์ทางการของ Python ก็ได้อธิบายกฎของตัวแปร local และ global ไว้อย่างละเอียดเช่นกัน


ดีบักไปพร้อมกับ AI! เทคนิคการแก้ NameError แบบสายฟ้าแลบ

คุณคงอยากจะลดเวลาที่ใช้ในการแก้ปัญหาข้อผิดพลาด แล้วเอาเวลาไปใช้กับงานสร้างสรรค์มากกว่าใช่ไหมครับ ใน럴 때, คู่หูที่ดีที่สุดก็คือ AI (เช่น ChatGPT หรือ Gemini) นั่นเอง

ตอนนี้ เวลาที่ผมเจอ `NameError` ผมมักจะขอความช่วยเหลือจาก AI ตามขั้นตอนต่อไปนี้เสมอ

  1. คัดลอกข้อความแสดงข้อผิดพลาดทั้งหมด: เลือกและคัดลอกข้อมูลข้อผิดพลาดทั้งหมดที่แสดงในเทอร์มินัล ตั้งแต่ `Traceback` ไปจนถึง `NameError: ...`
  2. แปะแล้วถาม AI: เปิดหน้าต่างแชทของ AI แล้วขอร้องว่า "ช่วยอธิบายสาเหตุของข้อผิดพลาด Python นี้ให้เข้าใจง่ายสำหรับมือใหม่หน่อยครับ" แล้วแปะข้อความแสดงข้อผิดพลาดที่คัดลอกมา
  3. ตรวจสอบโค้ดอีกครั้งตามคำใบ้ของ AI: ส่วนใหญ่แล้ว AI จะชี้สาเหตุที่แม่นยำได้ เช่น "ตัวแปรชื่อ 〇〇 ยังไม่ได้ถูกกำหนด อาจจะเกิดจากการสะกดผิด หรือเรียกใช้ก่อนที่จะกำหนดค่า"

เมื่อวันก่อน ผมก็เจอ `NameError` ตอนเขียนโค้ดเรียกใช้คีย์ของ dictionary (พจนานุกรม) แล้วหาสาเหตุเองไม่เจอ แต่พอโยนโค้ดทั้งหมดกับข้อผิดพลาดให้ AI มันก็บอกผมทันทีว่า "เวลาเรียกใช้คีย์ของ dictionary ต้องครอบด้วยเครื่องหมายคำพูด เช่น `'key_name'` แต่คุณไม่ได้ครอบไว้ ทำให้มันพยายามเรียกใช้เป็นตัวแปร จึงเกิด `NameError`"

การใช้ AI เป็นคู่หูในการดีบักแบบนี้ จะช่วยลดระยะเวลาในการแก้ไขปัญหาได้อย่างมาก ไม่ต้องกลัวข้อผิดพลาด แล้วมาพึ่งพา AI กันให้มากขึ้นเถอะครับ


3 นิสัยที่ดีเพื่อป้องกัน NameError ก่อนที่จะเกิดขึ้น

ความสามารถในการแก้ไขข้อผิดพลาดเป็นสิ่งสำคัญ แต่การเขียนโค้ดที่ไม่ให้เกิดข้อผิดพลาดตั้งแต่แรกนั้นคืออุดมคติ ที่นี่ ผมจะมาแนะนำ 3 นิสัยที่ผมปฏิบัติเพื่อลด `NameError`

1. ตั้งชื่อตัวแปรให้เข้าใจง่าย
ชื่อสั้นๆ อย่าง `x` หรือ `tmp` มักจะพิมพ์ผิดได้ง่าย และเมื่อกลับมาดูทีหลังก็จะจำไม่ได้ว่าเป็นตัวแปรสำหรับอะไร ขอแนะนำอย่างยิ่งให้ตั้งชื่อที่สื่อความหมายได้ เช่น `user_name` หรือ `total_price` แม้จะยาวขึ้นเล็กน้อยก็ตาม
2. ติดตั้ง Linter
Linter คือเครื่องมือที่ช่วยชี้ข้อผิดพลาดทางไวยากรณ์และบักที่อาจเกิดขึ้นได้แบบเรียลไทม์ขณะเขียนโค้ด ในโปรแกรมแก้ไขโค้ดที่มีฟังก์ชันครบครันอย่าง VSCode สามารถเพิ่ม Linter สำหรับ Python เช่น `Pylint` หรือ `Flake8` ได้อย่างง่ายดาย หากพยายามใช้ตัวแปรที่ยังไม่ได้กำหนดค่า โปรแกรมแก้ไขโค้ดจะแจ้งเตือนด้วยเส้นหยักหรือสัญลักษณ์อื่นๆ ก่อนที่จะรันโค้ดเสียอีก ซึ่งช่วยลด `NameError` ได้อย่างมาก
3. รันโค้ดบ่อยๆ
การรันโค้ดครั้งแรกหลังจากเขียนเสร็จไปแล้ว 100 บรรทัด จะทำให้การหาจุดที่เกิดข้อผิดพลาดนั้นยากมาก หากฝึกให้เป็นนิสัยที่จะตรวจสอบการทำงานทีละเล็กทีละน้อย เช่น เขียนสองสามบรรทัดแล้วรัน หรือสร้างฟังก์ชันหนึ่งตัวแล้วรัน จะทำให้การระบุตำแหน่งของสาเหตุข้อผิดพลาดนั้นง่ายขึ้นมาก

บทสรุป: ข้อผิดพลาดคือเครื่องหมายของการเติบโต!

ในครั้งนี้ ผมได้อธิบายถึงสาเหตุและวิธีแก้ไขที่เป็นรูปธรรมของ `NameError` ซึ่งเป็นเส้นทางที่มือใหม่ทุกคนต้องผ่าน พร้อมกับเล่าประสบการณ์ของผมประกอบ

เรามาทบทวนสามสาเหตุหลักของ `NameError` กันอีกครั้งนะครับ

  • พิมพ์ผิด: สะกดชื่อตัวแปรหรือฟังก์ชันผิด
  • ลำดับการทำงานผิดพลาด: พยายามเรียกใช้ตัวแปรก่อนที่จะกำหนดค่า
  • กำแพง Scope: เข้าถึงตัวแปรจากนอกขอบเขตที่ใช้งานได้ เช่น พยายามใช้ตัวแปรจากภายในฟังก์ชันที่ภายนอก

ข้อความแสดงข้อผิดพลาดเป็นคำใบ้สำคัญที่จะทำให้โค้ดของคุณทำงานได้ เมื่อเจอ `NameError` ให้คิดสบายๆ ว่า "อ๋อ Python กำลังบอกให้เราบอกชื่อที่มันไม่รู้จักสินะ" แล้วใจเย็นๆ หาสาเหตุ และอย่าลืมว่าเมื่อไหร่ที่เดือดร้อน ก็ยังมีคู่หูที่แข็งแกร่งอย่าง AI อยู่ด้วย

ทุกครั้งที่ก้าวข้ามข้อผิดพลาดไปได้หนึ่งครั้ง ทักษะการเขียนโปรแกรมของคุณก็จะพัฒนาขึ้นอย่างแน่นอน ข้อผิดพลาดไม่ใช่สิ่งที่น่ากลัว แต่เป็นครูที่ดีที่สุดที่จะทำให้คุณเติบโต เรามาสนุกกับการเขียนโปรแกรมด้วยกันต่อไปนะครับ!

สำหรับขั้นตอนต่อไป

หลังจากที่เชี่ยวชาญเรื่อง `NameError` แล้ว ลองมาเรียนรู้เกี่ยวกับ `TypeError` ซึ่งเป็นข้อผิดพลาดที่พบบ่อยถัดไปดูไหมครับ? ผมได้อธิบายวิธีแก้ไขข้อผิดพลาดที่เกิดจากความแตกต่างของชนิดข้อมูล (type) เช่น เมื่อพยายามบวกตัวเลขกับสตริง ด้วยวิธีที่เข้าใจง่ายเช่นเดียวกัน

➡️ ไปต่อที่ วิธีรับมือกับ TypeError (ข้อผิดพลาดเมื่อชนิดข้อมูลต่างกัน)