เป็นวิธีที่ดีที่สุดในการตรวจสอบว่าวัตถุที่กำหนดเป็นประเภทที่กำหนดคืออะไร? วิธีการเกี่ยวกับการตรวจสอบว่าวัตถุสืบทอดจากประเภทที่กำหนดหรือไม่
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
เป็นหรือเป็นประเภทที่สืบทอดมาจากstr
str
type(o) is str
จะกลับมาTrue
ถ้าหากว่าo
เป็น STR มันจะกลับมาFalse
ถ้าเป็นประเภทที่สืบทอดมาจากo
str
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)