ฉันจะรับจำนวนองค์ประกอบในรายการได้อย่างไร


1937

พิจารณาสิ่งต่อไปนี้:

items = []
items.append("apple")
items.append("orange")
items.append("banana")

# FAKE METHOD:
items.amount()  # Should return 3

ฉันจะรับจำนวนองค์ประกอบในรายการได้itemsอย่างไร


23
คุณกำลังถามจำนวนองค์ประกอบในรายการอย่างชัดเจน หากผู้ค้นหามาที่นี่เพื่อค้นหาขนาดของวัตถุในหน่วยความจำนี่เป็นคำถามและคำตอบจริงที่พวกเขากำลังค้นหา: ฉันจะกำหนดขนาดของวัตถุใน Python ได้อย่างไร
Aaron Hall

คำตอบ:


2640

len()ฟังก์ชั่นที่สามารถใช้กับประเภทที่แตกต่างกันในหลาม - ทั้งในตัวชนิดและประเภทห้องสมุด ตัวอย่างเช่น:

>>> len([1,2,3])
3

เอกสารทางการ 2.x อยู่ที่นี่: เอกสารทางการ 3.x อยู่ที่นี่:len()
len()


239

วิธีรับขนาดของรายการ

เพื่อหาขนาดของรายการใช้ฟังก์ชัน builtin len:

items = []
items.append("apple")
items.append("orange")
items.append("banana")

และตอนนี้:

len(items)

ผลตอบแทน 3

คำอธิบาย

ทุกอย่างใน Python เป็นวัตถุรวมถึงรายการ วัตถุทั้งหมดมีส่วนหัวของการจัดเรียงบางอย่างในการใช้งาน C

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

แต่ถ้าคุณกำลังตรวจสอบถ้าขนาดของรายการเป็นศูนย์หรือไม่ไม่ได้ใช้len- แทนใส่รายการในบริบทแบบบูล - มันถือว่าเป็นเท็จถ้าว่างที่แท้จริงมิฉะนั้น

จากเอกสาร

len(s)

ส่งคืนความยาว (จำนวนรายการ) ของวัตถุ อาร์กิวเมนต์อาจเป็นลำดับ (เช่นสตริงไบต์ tuple รายการหรือช่วง) หรือคอลเล็กชัน (เช่นพจนานุกรมชุดหรือชุดที่ตรึง)

lenถูกนำไปใช้กับ__len__จากdocของ data data :

object.__len__(self)

เรียกว่าใช้งานฟังก์ชันในlen()ตัว ควรคืนความยาวของวัตถุเป็นจำนวนเต็ม> = 0 นอกจากนี้วัตถุที่ไม่ได้กำหนดเมธอด__nonzero__()[ใน Python 2 หรือ__bool__()ใน Python 3] และ__len__()เมธอดส่งคืนค่าศูนย์จะถือว่าเป็นเท็จในบริบทบูลีน

และเรายังสามารถเห็นว่า__len__เป็นวิธีการของรายการ:

items.__len__()

ผลตอบแทน 3

ประเภท Builtin คุณสามารถรับlen(ความยาว) ของ

และในความเป็นจริงเราเห็นว่าเราสามารถรับข้อมูลนี้สำหรับประเภทที่อธิบายไว้ทั้งหมด:

>>> all(hasattr(cls, '__len__') for cls in (str, bytes, tuple, list, 
                                            xrange, dict, set, frozenset))
True

อย่าใช้lenเพื่อทดสอบรายการที่ว่างเปล่าหรือไม่มีข้อมูล

เพื่อทดสอบความยาวที่เฉพาะเจาะจงแน่นอนเพียงทดสอบความเท่าเทียมกัน:

if len(items) == required_length:
    ...

แต่มีกรณีพิเศษสำหรับการทดสอบรายการความยาวเป็นศูนย์หรือผกผัน ในกรณีนั้นอย่าทดสอบความเท่าเทียมกัน

นอกจากนี้อย่าทำ:

if len(items): 
    ...

เพียงทำ:

if items:     # Then we have some items, not empty!
    ...

หรือ

if not items: # Then we have an empty list!
    ...

ฉันอธิบายว่าทำไมที่นี่แต่สั้น ๆif itemsหรือif not itemsเป็นทั้งที่สามารถอ่านได้และมีประสิทธิภาพมากกว่า


75

ในขณะที่สิ่งนี้อาจไม่เป็นประโยชน์เนื่องจากความจริงที่ว่ามันฟังก์ชั่น "ออกจากกล่อง" มีความหมายมากกว่าการแฮ็คที่ค่อนข้างง่ายจะสร้างคลาสที่มีlengthคุณสมบัติ:

class slist(list):
    @property
    def length(self):
        return len(self)

คุณสามารถใช้มันได้เช่น:

>>> l = slist(range(10))
>>> l.length
10
>>> print l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

โดยพื้นฐานแล้วมันจะเหมือนกับรายการวัตถุโดยมีประโยชน์เพิ่มเติมจากการมีlengthคุณสมบัติที่เป็นมิตรกับ OOP

เช่นเคยไมล์สะสมของคุณอาจแตกต่างกันไป


19
เพื่อให้คุณรู้ว่าคุณสามารถทำได้length = property(len)และข้ามฟังก์ชัน wrapper บรรทัดเดียวและเก็บเอกสาร / วิปัสสนาของlenคุณสมบัติของคุณ
Tadhg McDonald-Jensen

17

นอกจากนี้lenคุณยังสามารถใช้operator.length_hint(ต้องการ Python 3.4+) สำหรับปกติlistทั้งสองจะเทียบเท่า แต่length_hintทำให้สามารถรับความยาวของ list-iterator ซึ่งอาจเป็นประโยชน์ในบางสถานการณ์:

>>> from operator import length_hint
>>> l = ["apple", "orange", "banana"]
>>> len(l)
3
>>> length_hint(l)
3

>>> list_iterator = iter(l)
>>> len(list_iterator)
TypeError: object of type 'list_iterator' has no len()
>>> length_hint(list_iterator)
3

แต่length_hintตามนิยามแล้วเป็นเพียง "คำใบ้" ดังนั้นเวลาส่วนใหญ่lenจึงดีกว่า

__len__ผมเคยเห็นหลายคำตอบบอกเข้าถึง สิ่งนี้ถูกต้องเมื่อจัดการกับคลาสที่มีอยู่ภายในlistแต่อาจนำไปสู่ปัญหากับคลาสที่กำหนดเองเนื่องจากlen(และlength_hint) ใช้การตรวจสอบความปลอดภัยบางอย่าง ตัวอย่างเช่นทั้งสองไม่อนุญาตให้มีความยาวหรือความยาวเชิงลบที่เกินค่าที่แน่นอน ( sys.maxsizeค่า) ดังนั้นจึงปลอดภัยกว่าที่จะใช้lenฟังก์ชั่นแทน__len__วิธีการ!


8

ตอบคำถามของคุณตามตัวอย่างที่ให้ไว้ก่อนหน้านี้:

items = []
items.append("apple")
items.append("orange")
items.append("banana")

print items.__len__()

15
ใน Python ชื่อที่ขึ้นต้นด้วยเครื่องหมายขีดล่างเป็นวิธีการแบบไม่ใช้ความหมายและไม่ควรใช้โดยผู้ใช้
Aaron Hall

2
1. __foo__: นี่เป็นเพียงการประชุมเป็นวิธีที่ระบบ Python จะใช้ชื่อที่จะไม่ขัดแย้งกับชื่อผู้ใช้ 2. _foo: นี่เป็นเพียงการประชุมวิธีสำหรับโปรแกรมเมอร์เพื่อระบุว่าตัวแปรเป็นแบบส่วนตัว (อะไรก็ตามที่มีความหมายใน Python) 3. __foo: สิ่งนี้มีความหมายที่แท้จริง: ล่ามมาแทนที่ชื่อนี้ด้วย_classname__fooเพื่อให้แน่ใจว่าชื่อจะไม่ทับซ้อนกับชื่อที่คล้ายกันในคลาสอื่น * ไม่มีรูปแบบอื่นของขีดล่างมีความหมายในโลกหลาม * ไม่มีความแตกต่างระหว่างคลาสตัวแปรโกลบอลและอื่น ๆ ในแบบแผนเหล่านี้
Shai Alon

4
คำถามและคำตอบนี้อธิบายว่าทำไมคุณไม่ควรใช้วิธีการพิเศษโดยตรงในฐานะผู้ใช้: stackoverflow.com/q/40272161/541136
Aaron Hall

@AaronHall แต่สำหรับฟังก์ชั่น len มันเกือบจะเหมือนกัน มันอาจเร็วกว่าสำหรับตัวแปรที่มีขนาดใหญ่มาก อย่างไรก็ตามฉันได้รับคะแนนของคุณและเราควรใช้ len (obj) และไม่ใช่ obj .__ len __ ()
Shai Alon

7

และเพื่อความสมบูรณ์ (การศึกษาเบื้องต้น) เป็นไปได้โดยไม่ต้องใช้len()ฟังก์ชั่น ฉันจะไม่เอาผิดสิ่งนี้เป็นตัวเลือกที่ดีอย่าโปรแกรมเช่นนี้ใน PYTHONแต่มันมีจุดประสงค์สำหรับการเรียนรู้อัลกอริทึม

def count(list):
    item_count = 0
    for item in list[:]:
        item_count += 1
    return item_count

count([1,2,3,4,5])

(เครื่องหมายจุดคู่ในlist[:]เป็นปริยายและเป็นตัวเลือกด้วย)

บทเรียนสำหรับโปรแกรมเมอร์ใหม่คือ: คุณไม่สามารถรับจำนวนไอเท็มในรายการโดยไม่นับในบางจุด คำถามจะกลายเป็น: เมื่อไหร่เวลาที่เหมาะสมที่จะนับพวกเขา ตัวอย่างเช่นรหัสประสิทธิภาพสูงเช่นการเชื่อมต่อการเรียกระบบสำหรับซ็อกเก็ต (เขียนเป็น C) connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);ไม่ได้คำนวณความยาวขององค์ประกอบ (ให้ความรับผิดชอบกับรหัสการโทร) ขอให้สังเกตว่าความยาวของที่อยู่จะถูกส่งไปตามเพื่อบันทึกขั้นตอนการนับความยาวก่อนหรือไม่ ตัวเลือกอื่น: การคำนวณมันอาจสมเหตุสมผลในการติดตามจำนวนรายการเมื่อคุณเพิ่มเข้าไปในวัตถุที่คุณส่ง จำไว้ว่าการใช้พื้นที่หน่วยความจำมากขึ้น ดูคำตอบ Naftuli เคย์

ตัวอย่างการติดตามความยาวเพื่อปรับปรุงประสิทธิภาพในขณะที่ใช้พื้นที่ในหน่วยความจำมากขึ้น โปรดทราบว่าฉันไม่เคยใช้ฟังก์ชั่น len () เพราะความยาวถูกติดตาม:

class MyList(object):
    def __init__(self):
        self._data = []
        self.length = 0 # length tracker that takes up memory but makes length op O(1) time


        # the implicit iterator in a list class
    def __iter__(self):
        for elem in self._data:
            yield elem

    def add(self, elem):
        self._data.append(elem)
        self.length += 1

    def remove(self, elem):
        self._data.remove(elem)
        self.length -= 1

mylist = MyList()
mylist.add(1)
mylist.add(2)
mylist.add(3)
print(mylist.length) # 3
mylist.remove(3)
print(mylist.length) # 2

ทำไมfor item in list[:]:? ทำไมfor item in list:ล่ะ นอกจากนี้ฉันจะใช้+= 1เพื่อเพิ่ม
ยาย

@GrannyAching ฉันพูดถึงโคลอนเสริม (ตัวระบุช่วง) อย่างชัดเจน ฉันปล่อยตัวระบุช่วงไว้ที่นั่นเพื่อการศึกษา - มันมีประโยชน์ที่จะรู้ว่ามันมีความหมาย รายการชนิด [] ถูกอนุมานเช่นกันตามที่คุณแนะนำเทียบเท่ากับรหัสของฉัน ตัวดำเนินการที่เพิ่มขึ้นนั้นเทียบเท่ากับการเพิ่ม 1 ไปยังตัวแปรที่มีอยู่ แต่จะสั้นกว่าในทุกกรณี ดังนั้นฉันจึงเห็นด้วยว่าควรใช้หากเป็นเหตุผลของคุณ ไม่ควรใส่รหัสนี้ในการผลิตที่ใดก็ได้ (ยกเว้นเมื่อเรียนรู้การเขียนโปรแกรม)
Jonathan Komar

0

ในแง่ของการlen()ใช้งานจริงนี่คือการใช้งาน C :

static PyObject *
builtin_len(PyObject *module, PyObject *obj)
/*[clinic end generated code: output=fa7a270d314dfb6c input=bc55598da9e9c9b5]*/
{
    Py_ssize_t res;

    res = PyObject_Size(obj);
    if (res < 0) {
        assert(PyErr_Occurred());
        return NULL;
    }
    return PyLong_FromSsize_t(res);
}

Py_ssize_tคือความยาวสูงสุดที่วัตถุสามารถมีได้ PyObject_Size()เป็นฟังก์ชันที่คืนค่าขนาดของวัตถุ หากไม่สามารถกำหนดขนาดของวัตถุได้จะส่งคืน -1 ในกรณีดังกล่าวบล็อกรหัสนี้จะถูกดำเนินการ:

if (res < 0) {
        assert(PyErr_Occurred());
        return NULL;
    }

และมีข้อยกเว้นเกิดขึ้น มิฉะนั้นบล็อกรหัสนี้จะถูกดำเนินการ:

return PyLong_FromSsize_t(res);

resซึ่งเป็นCจำนวนเต็มถูกแปลงเป็นไพ ธ อนlongและส่งคืน จำนวนเต็มหลามทั้งหมดจะถูกเก็บไว้longsตั้งแต่ Python 3


3
เหตุใดจึงรู้หรือรู้เรื่องการใช้งาน C
cs95

เนื่องจากคำถามนี้ไม่เฉพาะเจาะจงกับ CPython คำตอบนี้อาจทำให้เข้าใจผิด PyPy, IronPython, ... สามารถและนำไปใช้งานต่างกันได้
MSeifert
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.