เป็นวิธีที่ดีที่สุดในการตรวจสอบว่าวัตถุที่กำหนดเป็นประเภทที่กำหนดคืออะไร? วิธีการเกี่ยวกับการตรวจสอบว่าวัตถุสืบทอดจากประเภทที่กำหนดหรือไม่
oสมมติว่าผมมีวัตถุ ฉันจะตรวจสอบว่ามันเป็นstrอย่างไร
เป็นวิธีที่ดีที่สุดในการตรวจสอบว่าวัตถุที่กำหนดเป็นประเภทที่กำหนดคืออะไร? วิธีการเกี่ยวกับการตรวจสอบว่าวัตถุสืบทอดจากประเภทที่กำหนดหรือไม่
oสมมติว่าผมมีวัตถุ ฉันจะตรวจสอบว่ามันเป็นstrอย่างไร
คำตอบ:
ในการตรวจสอบว่าoเป็นอินสแตนซ์ของstrหรือคลาสย่อยใด ๆstrให้ใช้isinstance (นี่จะเป็นวิธี "canonical"):
if isinstance(o, str):
ในการตรวจสอบว่าประเภทของประเภทoนั้นแน่นอนstrหรือไม่ (ยกเว้นคลาสย่อย):
if type(o) is str:
ต่อไปนี้ใช้งานได้และอาจมีประโยชน์ในบางกรณี:
if issubclass(type(o), str):
ดูฟังก์ชั่นในตัวใน Python Library Reference สำหรับข้อมูลที่เกี่ยวข้อง
อีกหนึ่งหมายเหตุ: ในกรณีนี้ถ้าคุณใช้ Python 2 คุณอาจต้องการใช้:
if isinstance(o, basestring):
เพราะสิ่งนี้จะจับสตริง Unicode ( unicodeไม่ใช่คลาสย่อยของstr; ทั้งคู่strและunicodeคลาสย่อยของbasestring) โปรดทราบว่าbasestringไม่มีอยู่ใน Python 3 อีกต่อไปโดยที่มีการแยกสตริง ( str) และข้อมูลไบนารี ( bytes) อย่างเข้มงวด
อีกทางเลือกหนึ่งisinstanceรับของชั้นเรียน สิ่งนี้จะส่งคืนTrueหากoเป็นอินสแตนซ์ของคลาสย่อยใด ๆ ของ(str, unicode):
if isinstance(o, (str, unicode)):
type(a) is Object isinstance(a, Object)แต่ถ้าtype(a) is SubClassOfObjectไปแล้ว แต่type(a) is Object == False isinstance(a, Object) == Trueขวา?
a is bหมายถึง a และ b เป็นสิ่งเดียวกันนั่นคือการอ้างอิงไปยังเอนทิตีเดียวกันในหน่วยความจำ ดังนั้นaและbจะต้องเป็นระดับเดียวกันที่แน่นอนไม่ได้ subclasses isinstance()เช่นเดียวกับ ดูตัวอย่างstackoverflow.com/a/133024/1072212
ที่สุดวิธี Pythonic เพื่อตรวจสอบชนิดของวัตถุคือ ... ไม่ได้ไปตรวจสอบ
เนื่องจาก Python สนับสนุนการพิมพ์ดีดเป็ดคุณจึงควรtry...exceptใช้วิธีการของวัตถุในแบบที่คุณต้องการใช้ ดังนั้นหากฟังก์ชั่นของคุณกำลังมองหาวัตถุไฟล์ที่เขียนได้อย่าตรวจสอบว่ามันเป็นซับคลาสของfileเพียงลองใช้.write()วิธีการของมัน!
แน่นอนว่าบางครั้ง abstractions ที่ดีเหล่านี้ก็พังทลายและisinstance(obj, cls)เป็นสิ่งที่คุณต้องการ แต่ใช้เท่าที่จำเป็น
if hasattr(ob, "write") and callable(ob.write): หรือบันทึกการเข้าถึง dict ...func = getattr(ob, "write", None) if callable(func): ...
hasattrจะมีเฉพาะ AttributeError เท่านั้น - ดูที่: docs.python.org/3.4/library/functions.html#hasattr
isinstance(o, str)จะกลับมาTrueถ้าoเป็นหรือเป็นประเภทที่สืบทอดมาจากstrstr
type(o) is strจะกลับมาTrueถ้าหากว่าoเป็น STR มันจะกลับมาFalseถ้าเป็นประเภทที่สืบทอดมาจากostr
isinstanceและtype(var) == type('')ไม่ชัดเจน
หลังจากคำถามที่ถูกถามและตอบชนิดคำแนะนำที่ถูกเพิ่มเข้าไปในหลาม พิมพ์คำใบ้ใน Python อนุญาตให้ตรวจสอบประเภท แต่แตกต่างจากภาษาที่พิมพ์แบบคงที่ คำใบ้ประเภทใน Python จะเชื่อมโยงประเภทของอาร์กิวเมนต์ที่คาดหวังกับฟังก์ชั่นเป็นข้อมูลที่สามารถเข้าถึงได้ที่เชื่อมโยงกับฟังก์ชั่นรันไทม์ซึ่งจะช่วยให้สามารถตรวจสอบประเภทได้ ตัวอย่างของไวยากรณ์คำใบ้ประเภท:
def foo(i: int):
return i
foo(5)
foo('oops')
ในกรณีนี้เราต้องการให้เกิดข้อผิดพลาดที่จะถูกเรียกสำหรับตั้งแต่ประเภทข้อเขียนของการโต้แย้งคือfoo('oops') intคำใบ้ประเภทที่เพิ่มเข้ามาจะไม่ทำให้เกิดข้อผิดพลาดเกิดขึ้นเมื่อสคริปต์ทำงานตามปกติ อย่างไรก็ตามมันเพิ่มคุณสมบัติให้กับฟังก์ชั่นที่อธิบายถึงประเภทที่คาดหวังว่าโปรแกรมอื่นสามารถสืบค้นและใช้เพื่อตรวจสอบข้อผิดพลาดประเภท
หนึ่งในโปรแกรมอื่น ๆ เหล่านี้ที่สามารถใช้เพื่อค้นหาข้อผิดพลาดประเภทคือmypy:
mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"
(คุณอาจต้องติดตั้งmypyจากผู้จัดการแพ็คเกจฉันไม่คิดว่ามันมาพร้อมกับ CPython แต่ดูเหมือนจะมี "ทางการ" ในระดับหนึ่ง)
การตรวจสอบประเภทด้วยวิธีนี้แตกต่างจากการตรวจสอบประเภทในภาษาที่รวบรวมแบบคงที่ เนื่องจากประเภทเป็นแบบไดนามิกใน Python การตรวจสอบประเภทจะต้องทำที่รันไทม์ซึ่งกำหนดค่าใช้จ่าย - แม้ในโปรแกรมที่ถูกต้อง - ถ้าเรายืนยันว่ามันเกิดขึ้นในทุกโอกาส การตรวจสอบประเภทที่ชัดแจ้งอาจมีข้อ จำกัด มากกว่าที่จำเป็นและทำให้เกิดข้อผิดพลาดที่ไม่จำเป็น (เช่นอาร์กิวเมนต์จำเป็นต้องเป็นlistประเภทที่แน่นอนหรือเป็นสิ่งที่สามารถทำซ้ำได้หรือไม่?)
ข้อดีของการตรวจสอบประเภทที่ชัดเจนคือมันสามารถตรวจจับข้อผิดพลาดก่อนหน้านี้และให้ข้อความแสดงข้อผิดพลาดที่ชัดเจนกว่าการพิมพ์เป็ด ข้อกำหนดที่แน่นอนของประเภทเป็ดสามารถแสดงด้วยเอกสารภายนอกเท่านั้น (หวังว่ามันจะละเอียดและแม่นยำ) และข้อผิดพลาดจากประเภทที่เข้ากันไม่ได้สามารถเกิดขึ้นได้ไกลจากที่มา
คำแนะนำประเภทของ Python มีไว้เพื่อเสนอการประนีประนอมซึ่งสามารถระบุและตรวจสอบประเภท แต่ไม่มีค่าใช้จ่ายเพิ่มเติมในระหว่างการเรียกใช้รหัสปกติ
typingตัวแปรประเภทแพคเกจข้อเสนอพิเศษที่สามารถนำมาใช้ในคำแนะนำที่เป็นประเภทที่จะแสดงพฤติกรรมที่จำเป็นโดยไม่ต้องมีประเภทโดยเฉพาะอย่างยิ่ง ตัวอย่างเช่นมันมีตัวแปรเช่นIterableและCallableคำแนะนำเพื่อระบุความต้องการประเภทใด ๆ ที่มีพฤติกรรมเหล่านั้น
ในขณะที่คำแนะนำประเภทเป็นวิธีการตรวจสอบชนิดของงูเหลือมที่มากที่สุด แต่บ่อยครั้งที่ Pythonic ชนิดนี้ไม่สามารถตรวจสอบประเภทได้ทั้งหมดและพึ่งพาการพิมพ์เป็ด คำใบ้ประเภทนี้ค่อนข้างใหม่และคณะลูกขุนยังคงปรากฏต่อไปเมื่อเป็น Pythonic solution ที่สุด การเปรียบเทียบที่ค่อนข้างไม่มีข้อโต้แย้ง แต่โดยทั่วไปมาก: คำแนะนำประเภทให้รูปแบบของเอกสารที่สามารถบังคับใช้อนุญาตให้สร้างรหัสก่อนหน้านี้และง่ายต่อการเข้าใจข้อผิดพลาดสามารถจับข้อผิดพลาดที่พิมพ์เป็ดไม่สามารถและสามารถตรวจสอบแบบคงที่ ความรู้สึก แต่มันยังคงอยู่นอกรันไทม์) ในทางกลับกันการพิมพ์เป็ดเป็นวิธี Pythonic มาเป็นเวลานานไม่ได้กำหนดค่าใช้จ่ายทางปัญญาของการพิมพ์แบบสแตติกมีความละเอียดน้อยกว่าและยอมรับทุกประเภทที่ใช้ได้
mypyเป็นโมดูล Python ที่ใช้importlibในการเข้าถึงข้อมูลนั้น ไม่ว่าจะเป็น "การตรวจสอบประเภทคงที่" เป็นคำถามเชิงปรัชญา แต่แตกต่างจากสิ่งที่คาดหวังมากที่สุดเนื่องจากล่ามภาษาปกติและเครื่องจักรนำเข้ามีส่วนเกี่ยวข้อง
นี่คือตัวอย่างว่าทำไมการพิมพ์เป็ดจึงเป็นเรื่องที่ชั่วร้ายโดยที่ไม่รู้ว่ามันอันตรายเมื่อไร ตัวอย่างเช่น: นี่คือรหัส Python (อาจเว้นการเยื้องที่เหมาะสม) โปรดทราบว่าสถานการณ์นี้สามารถหลีกเลี่ยงได้โดยการดูแล isinstance และ issubclassof เพื่อให้แน่ใจว่าเมื่อคุณต้องการเป็ดจริง ๆ คุณจะไม่ได้รับระเบิด
class Bomb:
def __init__(self):
""
def talk(self):
self.explode()
def explode(self):
print "BOOM!, The bomb explodes."
class Duck:
def __init__(self):
""
def talk(self):
print "I am a duck, I will not blow up if you ask me to talk."
class Kid:
kids_duck = None
def __init__(self):
print "Kid comes around a corner and asks you for money so he could buy a duck."
def takeDuck(self, duck):
self.kids_duck = duck
print "The kid accepts the duck, and happily skips along"
def doYourThing(self):
print "The kid tries to get the duck to talk"
self.kids_duck.talk()
myKid = Kid()
myBomb = Bomb()
myKid.takeDuck(myBomb)
myKid.doYourThing()
class EvilDuck(Duck)และแทนที่พูดคุย () หรือมีโอกาสมากขึ้นที่มีclass ChineseCancerDuck(Duck)ผลข้างเคียงที่น่ารังเกียจซึ่งไม่ปรากฏขึ้นจนกว่าจะถึงปีต่อมา คุณควรจะดูแลลูกของคุณให้ดีขึ้น (และทดสอบของเล่นของเธออย่างถี่ถ้วน :)
__file__แอ็ตทริบิวต์ (โดยทั่วไปจะใช้เพื่อระบุออบเจ็กต์คล้ายไฟล์) เพื่อแปลความหมายอย่างอื่น
isinstance(o, str)
ฉันคิดว่าสิ่งที่ยอดเยี่ยมเกี่ยวกับการใช้ภาษาแบบไดนามิกเช่น Python คือคุณไม่ควรตรวจสอบสิ่งนั้น
ฉันแค่จะเรียกวิธีการที่จำเป็นในวัตถุของคุณและจับ AttributeErrorฉันจะเรียกวิธีการที่จำเป็นบนวัตถุและจับของคุณหลังจากนี้จะช่วยให้คุณสามารถเรียกวิธีการของคุณกับวัตถุอื่น ๆ (ดูเหมือนไม่เกี่ยวข้อง) เพื่อทำงานที่แตกต่างกันเช่นการเยาะเย้ยวัตถุสำหรับการทดสอบ
ฉันใช้มันเยอะมากเมื่อนำข้อมูลออกจากเว็บurllib2.urlopen()ซึ่งคืนไฟล์เหมือนวัตถุ สิ่งนี้สามารถส่งผ่านไปยังเกือบทุกวิธีที่อ่านจากไฟล์เพราะมันใช้read()วิธีการเดียวกันกับไฟล์จริง
แต่ฉันแน่ใจว่ามีเวลาและสถานที่สำหรับการใช้isinstance()งานมิฉะนั้นมันอาจจะไม่อยู่ที่นั่น :)
สำหรับการตรวจสอบประเภทที่ซับซ้อนยิ่งขึ้นฉันชอบวิธีการตรวจสอบของtypeguardโดยอ้างอิงจากคำอธิบายประกอบแบบ python:
from typeguard import check_type
from typing import List
try:
check_type('mylist', [1, 2], List[int])
except TypeError as e:
print(e)
คุณสามารถทำการตรวจสอบที่ซับซ้อนมากในแบบที่สะอาดและอ่านง่าย
check_type('foo', [1, 3.14], List[Union[int, float]])
# vs
isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo)
คุณสามารถตรวจสอบประเภทของตัวแปรโดยใช้ __name__ ของประเภท
Ex:
>>> a = [1,2,3,4]
>>> b = 1
>>> type(a).__name__
'list'
>>> type(a).__name__ == 'list'
True
>>> type(b).__name__ == 'list'
False
>>> type(b).__name__
'int'
ถึงฮูโก้:
คุณอาจหมายถึงlistมากกว่าarrayแต่ชี้ไปที่ปัญหาทั้งหมดด้วยการตรวจสอบชนิด - คุณไม่ต้องการทราบว่าวัตถุที่เป็นปัญหานั้นเป็นรายการหรือไม่คุณต้องการทราบว่าเป็นลำดับหรือไม่หรือเป็นวัตถุเดียว ดังนั้นลองใช้มันเหมือนลำดับ
สมมติว่าคุณต้องการเพิ่มวัตถุในลำดับที่มีอยู่หรือถ้าเป็นลำดับของวัตถุให้เพิ่มทั้งหมด
try:
my_sequence.extend(o)
except TypeError:
my_sequence.append(o)
เคล็ดลับอย่างหนึ่งก็คือถ้าคุณกำลังทำงานกับสตริงและ / หรือลำดับของสตริง - นั่นเป็นเรื่องยากเนื่องจากสตริงมักจะคิดว่าเป็นวัตถุเดียว แต่ก็เป็นลำดับของตัวละครด้วยเช่นกัน ยิ่งไปกว่านั้นเนื่องจากเป็นลำดับของสตริงความยาวเดี่ยว
ฉันมักจะเลือกที่จะออกแบบ API ของฉันเพื่อที่จะยอมรับเฉพาะค่าเดียวหรือลำดับ - มันทำให้ง่ายขึ้น มันไม่ยากเลยที่จะใส่[ ]ค่าเดียวของคุณเมื่อคุณผ่านมันหากจำเป็น
(แม้ว่าสิ่งนี้อาจทำให้เกิดข้อผิดพลาดกับสตริงได้เนื่องจากมีลักษณะดังนี้ (เป็น) ลำดับ)
วิธีง่ายๆในการตรวจสอบประเภทคือการเปรียบเทียบกับสิ่งที่คุณรู้ประเภท
>>> a = 1
>>> type(a) == type(1)
True
>>> b = 'abc'
>>> type(b) == type('')
True
ฉันคิดว่าวิธีที่ดีที่สุดคือการพิมพ์ตัวแปรของคุณให้ดี คุณสามารถทำได้โดยใช้ห้องสมุด "พิมพ์"
ตัวอย่าง:
from typing import NewType
UserId = NewType ('UserId', int)
some_id = UserId (524313) `
คุณสามารถตรวจสอบกับบรรทัดด้านล่างเพื่อตรวจสอบประเภทของตัวอักษรที่ได้รับค่าคือ:
def chr_type(chrx):
if chrx.isalpha()==True:
return 'alpha'
elif chrx.isdigit()==True:
return 'numeric'
else:
return 'nothing'
chr_type("12)