2009-10-04 120 views
2

我有一個Python中的情況(咳嗽,家庭作業),我需要將給定列表中的每個元素乘以指定次數並返回元素的輸出。問題是給出的樣本輸入是不同類型的。例如,一個案例可能會輸入一個字符串列表,其中的元素需要相乘,而其他元素可以是整數。所以我的返回類型需要改變。我想這樣做,而不必測試每種類型的對象。有沒有辦法做到這一點?我知道在C#中我可以只使用「var」,但我不知道在Python中是否存在這樣的事情?在Python中聲明未知類型變量?

我意識到變量不必聲明,但在這種情況下,我不能看到任何方式。這裏是我所做的功能:

def multiplyItemsByFour(argsList): 

output = ???? 

for arg in argsList: 
     output += arg * 4 

return output 

看看我需要添加到輸出變量。如果我只是嘗試在第一行刪除輸出分配,則會出現該變量未定義的錯誤。但是,如果我爲空字符串賦值0或「」,可能會拋出異常,因爲您不能將3添加到字符串中,或​​者將3添加到整數等等。樣本輸入和輸出:

Input: ('a','b') Output: 'aaaabbbb' 
Input: (2,3,4) Output: 36 

謝謝!

+0

請確保您在考試前閱讀了Python。大多數動態語言如Python不需要類型聲明 – Perpetualcoder 2009-10-04 02:15:43

+2

對於downvoter,我意識到這是作業,但問題與實際的作業分配無關。這個問題可以適用於任何事情。 – Austin 2009-10-04 02:24:31

+0

請解釋「乘以一個列表」的含義。從評論到其中一個答案,很明顯,你不是指Python中運算符「*」的普通語義(即複製列表)。 – 2009-10-04 02:43:42

回答

2

Python非常容易。您需要獲取列表中的數據類型 - 在第一項 - type(argsList [0])上使用type()函數。然後初始化輸出(你現在已經有了?),你需要這個類型的'零'或者nul值。因此,正如INT()或浮動()或STR()返回零或NUL將其類型所以將輸入(argsList [0])()返回您的列表中有任何類型的零或NUL值。

所以,這裏是一個小的修改你的函數:

def multiplyItemsByFour(argsList): 
    output = type(argsList[0])() 
    for arg in argsList: 
     output += arg * 4 
    return output 

工程與:: argsList = [1, 2, 3, 4][1.0, 2.0, 3.0, 4.0]"abcdef" ...等,

+0

謝謝,這完美的作品!我真的很好奇如何做到這一點,而不是簡單地讓別人解決我的功課。你們都做到了:)這可以在未來派上用場!這些其他解決方案中的一部分可以工作,但這是最簡單和最明確的。 – Austin 2009-10-04 17:43:19

+0

很高興幫助。祝你好運,並感謝您的支票。 – 2009-10-05 03:45:14

1

你不需要在python中聲明變量類型;一個變量具有分配給它的任何類型。

編輯:

爲了解決重述問題,試試這個:

def multiplyItemsByFour(argsList): 

output = argsList.pop(0) * 4 

for arg in argsList: 
     output += arg * 4 

return output 

(這可能不是這樣做的最Python的方式,但它至少應該開始新的輸出變量爲正確的類型,假設整個列表是相同類型的)

+0

是的,但變量必須有一個分配。如果我需要添加或增加變量並且沒有定義,我會在賦值之前得到一個「局部變量」輸出。「 – Austin 2009-10-04 02:18:43

+0

如果xyz之前沒有出現在xyz * 6中,您會期望什麼?你總是可以用try:來包裝東西,除了NameError: – foosion 2009-10-04 02:25:53

+0

是的,這是一個好主意。這似乎是我應該能夠做到這一點,而不必嘗試/趕上。我應該能夠說出類似output = Nothing的東西,並且稍後定義類型。 – Austin 2009-10-04 02:27:47

0

不需要測試對象,只需乘以!

'this is a string' * 6 
14 * 6 
[1,2,3] * 6 

一切只是工作

1

Python是動態類型的,你並不需要聲明一個變量的類型,因爲一個變量沒有類型,只有值做。

def do_something(x): 
    return x * 5 

這會爲你傳遞給它的任何x工作,實際結果取決於什麼類型x值有(任何變量可以存儲任何價值,它的生命週期中的值不會改變它的類型)。如果x包含一個數字,它只會執行常規乘法,如果它包含一個字符串,則該字符串將連續重複五次,對於列表,並且它將重複該列表五次,依此類推。對於自定義類型(類),它取決於該類是否具有爲乘法運算符定義的操作。

+0

但是,如果需要添加x,該怎麼辦?我不能簡單地說x * = 3,因爲它期望x已經被定義。如果我不知道最初分配的是什麼類型,我就無法定義它。我不能說x = 0,然後再對它進行操作,因爲它可能是我正在處理的一個字符串。 – Austin 2009-10-04 02:29:33

+0

你不要指定它的類型。一個變量沒有一個類型,它的值是。任何變量都可以包含任何通用對象。 – geoffspear 2009-10-04 02:39:57

+0

是的,你可以說'x * = 3'。是的,'x'已經被定義 - 它正好在函數參數列表中,這就是它的定義。不,你不需要一個類型來在Python中聲明變量。 – 2009-10-04 02:42:58

6
def fivetimes(anylist): 
    return anylist * 5 

正如你看到的,如果你給一個列表的說法,沒有必要對任何轉讓任何以「相乘的給定次數,並返回輸出」。你講一個給出的列表; 如果不是(最自然的方式)作爲你的函數的參數,它是如何給予給你的?不是那麼重要 - 如果它是一個全局變量,作爲參數的對象的屬性等等,這仍然不需要任何分配。

如果你是「homeworkically」從使用*運營商列表的禁止,只需要實現它自己,這需要分配,但沒有聲明:

def multiply_the_hard_way(inputlist, multiplier): 
    outputlist = [] 
    for i in range(multiplier): 
     outputlist.extend(inputlist) 
    return outputlist 

你可以簡單地使空列表「神奇的出現」:不需要將其「聲明」爲任何任何東西,它是一個空列表,Python編譯器知道它以及您或代碼的任何讀者。將其綁定到名稱outputlist並不要求您執行任何特殊的儀式,只是綁定(又名作業)本身:名稱沒有類型,只有對象有類型...這就是Python! - )

編輯:OP現在說輸出不能是一個列表,而是int,float,或者可能是字符串,並且他沒有被指示什麼。我要求澄清 - 將列表乘以一個列表總是返回一個列表,顯然他必須表示與他原先所說的不同的東西,他必須乘以一個列表。同時,這是另一個閱讀心靈的嘗試。也許他必須返回一個列表,其中輸入列表的每個項目都乘以相同的因子(無論該項目是int,float,string,list,...)。那好:

define multiply_each_item(somelist, multiplier): 
    return [item * multiplier for item in somelist] 

看,不用動手^ H^H^H^H^^ h分配。 (這被稱爲「列表理解」,順便說一句)。他需要(比如說)將每個列表項目乘以(如果不是這樣,但是我的頭腦可能會受到我的錫紙帽子的干擾,因爲它需要(比如說)將每個列表項目乘以如果他們是同一類型的第一個項目,但回報他們爲他們的原始類型,從而例如

>>> mystic(['zap', 1, 23, 'goo'], 2) 
['zapzap', 11, 2323, 'googoo'] 
>>> mystic([23, '12', 15, 2.5], 2) 
[46, '24', 30, 4.0] 

即使這樣高規格的神祕可以accomodated ...:

>>> def mystic(alist, mul): 
... multyp = type(alist[0]) 
... return [type(x)(mul*multyp(x)) for x in alist] 
... 

...雖然我非常喜歡d這個規範實際上是編碼在這個家庭作業的神祕符文中的。幾乎任何一個精確的規範都可以被實現,或者被證明是不可能的(通過要求你解決暫停問題或者要求P == NP,比如;-))。這可能需要一些工作(例如「證明四色定理」);但是仍然少於神奇地描述實際規格是什麼,或者來自一系列相互矛盾的觀察,沒有例子等。雖然我們在日常工作中作爲軟件開發人員(當我們不得不面對的一切都是功課時,我們都會遇到很多這樣的情況),我們當然會遇到很多這樣的案例(並且必須解決它們才能贏得我們的日常麪包; )。

EditEdit:終於看到了一個精確的規格我想指出,我已經實施了一個,反正這裏又來了:

def multiplyItemsByFour(argsList): 
    return [item * 4 for item in argsList] 

EditEditEdit:最後/終於看到了一個更精確的規格,用(豪華! - )例子

Input: ('a','b') Output: 'aaaabbbb' Input: (2,3,4) Output: 36 

那麼接下來有什麼希望它的總和(你不能使用sum,因爲它不會在輸入列表中的項目的處理字符串),分別乘以四。我首選的方案:

def theFinalAndTrulyRealProblemAsPosed(argsList): 
    items = iter(argsList) 
    output = next(items, []) * 4 
    for item in items: 
    output += item * 4 
    return output 

如果你使用一些結構,如內置插件itemsiter的禁止,還有許多其他的可能性(略遜一籌的),例如:

def theFinalAndTrulyRealProblemAsPosed(argsList): 
    if not argsList: return None 
    output = argsList[0] * 4 
    for item in argsList[1:]: 
    output += item * 4 
    return output 

對於一個空的argsList,第一個版本返回[],第二個返回None - 不知道你應該在那個角落裏幹什麼。

+0

謝謝;這就說得通了。然而,輸出不是一個列表。輸出將是一個字符串,整型,浮點等,我不知道輸出類型是什麼。我不能說輸出* = x,因爲它期望輸出已經被定義。但是,我無法定義它,因爲要定義它,我必須說output =「」或output = 0等。所以我可能必須手動測試列表中的類型,然後將輸出變量分配給該類型。 – Austin 2009-10-04 02:35:00

+0

@奧斯汀,到目前爲止你想要做的確切,精確的規格看起來非常模糊和狡猾 - 原來你說你需要乘以一個對象列表,現在結果不能是一個列表等等;請編輯你的問題來澄清,你不能期望讀心術 - 當然你的家庭作業的規格書寫在某處,對吧?!與此同時,我會編輯我的答案,以探討其他方式可能會讀你瘋狂模糊的話。 – 2009-10-04 02:39:19

+0

我的不好。這是漫長的一天:)我會編輯這個問題。 – Austin 2009-10-04 02:43:53

2

我的猜測是你作業的目的是讓你接觸到「鴨子打字」。基本的想法是,你不必擔心類型太多,你只是擔心行爲是否正常工作。一個典型的例子:

def add_two(a, b): 
    return a + b 

print add_two(1, 2) # prints 3 

print add_two("foo", "bar") # prints "foobar" 

print add_two([0, 1, 2], [3, 4, 5]) # prints [0, 1, 2, 3, 4, 5] 

注意,當你def Python中的函數,你沒有任何位置聲明返回類型。基於它的參數,相同的函數返回不同的類型是完全可以的。它甚至被認爲是一種美德;認爲在Python中我們只需要add_two()的一個定義,我們可以添加整數,添加浮點數,連接字符串和連接列表。靜態類型語言需要多個實現,除非它們有一個轉義,例如variant,但是Python是動態類型的。 (Python是強類型的,但是是動態類型的,有些人會告訴你Python是弱類型的,但它不是,在JavaScript等弱類型語言中,表達式1 + "1"會給你2的結果;在Python中,這個表達式只是引發TypeError異常。)

嘗試測試參數以找出它們的類型,然後根據類型做事情被認爲是非常糟糕的樣式。如果你需要讓你的代碼健壯,你可以隨時使用try塊:

def safe_add_two(a, b): 
    try: 
     return a + b 
    except TypeError: 
     return None 

又見duck typing的維基百科頁面。

+0

謝謝!我明白你的意思。我不知道有這個詞。我的印象是,Python中的動態類型意味着我可以簡單地定義變量並在稍後爲其指定一個類型,但看起來像有一個問題。我會嘗試try塊,看看它是怎麼回事。 – Austin 2009-10-04 03:12:12

+0

Python中的動態類型有兩個主要部分:(0)未聲明變量;你所做的是將一個名字「綁定」到一個對象; (1)類型在運行時被檢查,所以你不需要聲明事情。如果你執行代碼「a = 1」,實際發生的事情就是現在將名字「a」綁定到一個整數類型的對象上(在某些範圍內,可能是全局的,可能是本地的),值爲1。對於母雞來說,合法地說'a =「foo」'並將名稱「a」重新綁定到值爲「foo」的字符串對象。然後,因爲類型在必須被檢查之前不會被檢查,所以鴨子輸入功能是可能的。 – steveha 2009-10-04 04:40:15

+0

try塊只是一個如何編寫try塊的例子;你幾乎可以肯定不需要你的作業。在Python中,簡單地讓異常發生通常是最佳實踐。在一般情況下,'add_two()'幾乎肯定比'safe_add_two()'更可取。如果呼叫者需要防彈措施,呼叫者應該將呼叫包裝在try塊中。如果您將錯誤的參數傳遞給'add_two()',那麼異常的回溯將直接指向導致錯誤的代碼行; 'safe_add_two()'掩蓋了實際的錯誤。 – steveha 2009-10-04 04:43:04

0

嘗試這種情況:

​​

地圖執行列表(返回一個新的列表)中的每個元素傳入的函數,然後總和就在+ =上的列表中。

+0

輸入可以包含字符串,sum()不接受字符串。 – 2009-10-04 04:10:10

+0

好吧,並沒有打敗所有,但只要您指定計算而不指定默認值,這個想法是相同的。在用reduce(+,nextstep)替換sum的例子應該工作。 – stonemetal 2009-10-04 18:10:13

2

你確定這是爲Python初學者?對我來說,要做到這一點最徹底的方法是減少()和拉姆達,這兩者都是不典型的初學者工具,有時甚至鼓勵有經驗的Python程序員:

def multiplyItemsByFour(argsList): 
    if not argsList: 
     return None 
    newItems = [item * 4 for item in argsList] 
    return reduce(lambda x, y: x + y, newItems) 

像亞歷克斯·馬爾泰利,我已經拋出在開始時返回None的空列表的快速測試。請注意,如果您使用Python 3,則必須導入functools才能使用reduce()。

本質上,減少(拉姆達...)解決方案與使用第一個輸入項目設置累加器,然後處理其餘輸入項目的其他建議非常相似;但簡單得多。

+0

您也可以'導入運算符'然後使用'運算符。添加'而不是你寫的lambda來總結兩個數字。我已經將這看作是使用鴨子打字減少列表的典型方法。令我驚訝的是,添加到Python 2.3中的'sum()'不能這樣工作。 – steveha 2009-10-04 07:17:24

+0

@ steveha:有趣。文檔需要注意的一點是,operator.add用於數字,而operator.concat用於序列(包括字符串)。但的確,添加像'+'這樣的運算符(而concat實際上只是連接)。儘管如此,對於這樣一個簡短的例子,我喜歡避免導入,尤其是因爲它不需要導入(除非使用Python 3,如前所述)。 – 2009-10-04 23:28:49

+0

@steveha:我同意你sum()應該是重複應用'+'運算符,特別是考慮到operator.add的實際行爲。 – 2009-10-04 23:34:02

0

如果您只是想填寫代碼中的空白,您可以嘗試設置object=arglist[0].__class__()以使其爲該類的零等效值。

>>> def multiplyItemsByFour(argsList): 
    output = argsList[0].__class__() 
    for arg in argsList: 
      output += arg * 4 
    return output 

>>> multiplyItemsByFour('ab') 
'aaaabbbb' 
>>> multiplyItemsByFour((2,3,4)) 
36 
>>> multiplyItemsByFour((2.0,3.3)) 
21.199999999999999 

如果列表爲空,則會崩潰,但您可以在函數的開頭檢查該情況並返回任何您認爲合適的值。

+0

只要說'output = argsList [0]',然後修改for循環以便不在列表中添加第零項,會更好更簡單。否則,你要求麻煩...例如,製作一個類似'int'的類K是合法的,除非它的默認值是1而不是0.請參閱我的長答案以獲得更多關於此的想法。 – steveha 2009-10-04 06:59:48

1

你給這些樣品輸入和輸出:

輸入:( '一個', 'b')的輸出: 'aaaabbbb' 輸入:(2,3,4)輸出:36

我不不想爲你寫作業的解決方案,但我想引導你朝正確的方向發展。但是我仍然不確定自己明白你的問題是什麼,因爲根據我的理解,這個問題似乎對Python類的介紹有點困難。

解決這個問題的最簡單的方法是要將參數傳遞給列表。然後,您可以查看列表中的第一個項目,並從中獲益。這是一個需要調用者在兩個項目的列表來傳遞一個函數:

def handle_list_of_len_2(lst): 
    return lst[0] * 4 + lst[1] * 4 

現在,我們怎樣才能使這個延長兩年的項目?那麼,在您的示例代碼中,您不確定要將什麼分配給您的變量輸出。如何分配lst [0]?然後它總是有正確的類型。然後,您可以循環遍歷所有其他元素,然後使用+ =累加到您的輸出變量中,如您所寫。如果您不知道如何遍歷項目列表,但跳過列表中的第一件事,Google會搜索「python list slice」。

現在,我們如何才能使這不需要用戶將所有東西打包到列表中,而只需調用函數?我們真正想要的是以某種方式接受用戶想要傳遞給函數的任何參數,並從中列出一個列表。也許有特殊的語法來聲明一個函數,告訴Python你只需要將參數捆綁到一個列表中。您可能會檢查一個good tutorial,看看它如何定義一個函數。

現在我們已經涵蓋了(非常普遍)如何使用+ =來累積答案,讓我們考慮其他方法來累積答案。如果你知道如何使用列表理解,你可以使用其中的一個返回基於參數列表的新列表,每個參數都執行乘法;你可以以某種方式將列表縮小爲單個項目並返回。 Python 2.3和更新版本有一個名爲sum()的內置函數,您可能想要閱讀它。 [編輯:噢德拉,sum()只適用於數字。見末尾加註。]

我希望這有助於。如果您仍然很困惑,我建議您聯繫您的老師並要求澄清。祝你好運。

P.S. Python 2.x有一個名爲reduce()的內置函數,可以使用reduce()實現sum()。然而,Python的創建者認爲最好使用sum(),事實上他從Python 3.0中刪除了reduce()(好吧,他把它移到了一個名爲functools的模塊中)。

P.P.S.如果你能夠理解列表理解,那麼還有一件事需要考慮。如果您使用列表理解,然後將結果傳遞給sum(),則會構建一個列表以供使用,然後丟棄。如果我們可以得到結果,它會不會很整潔,但是不是構建整個列表然後丟棄它,而是我們可以讓sum()函數儘可能快地消耗列表項目?你可能想讀這個:Generator Expressions vs. List Comprehension

編輯:呵呵,我認爲Python的sum()內建將使用鴨打字。實際上它只記錄在數字上。我很失望!我將不得不搜索並查看是否有任何關於此的討論,並瞭解他們爲什麼按照他們的方式進行了討論。他們可能有很好的理由。同時,你可以使用你的+ =解決方案。對於那個很抱歉。

編輯:好的,閱讀其他答案,我現在注意到兩種方式建議剝離列表中的第一個元素。

爲了簡單起見,因爲你看起來像一個Python初學者,所以我建議使用output = lst[0],然後使用列表切片來跳過列表中的第一項。然而,Wooble在他的回答中建議使用output = lst.pop(0)這是一個非常乾淨的解決方案:它在列表中獲得第零個東西,然後您可以在列表中循環,並自動跳過第零個東西。但是,這個「變異」列表!如果像這樣的函數沒有「副作用」,例如修改傳遞給它的列表,那更好。 (除非該列表是專爲該函數調用而創建的特定列表,例如*args列表。)另一種方法是使用「列表切片」技巧製作刪除第一個項目的列表副本。 Alex Martelli提供了一個如何使用稱爲iter()的Python特性創建「迭代器」的示例,然後使用迭代器獲取「下一個」事物。由於迭代器尚未使用,接下來就是列表中的第零件。這不是一個真正的初學者解決方案,但它是在Python中執行此操作最優雅的方式;你可以將一個非常大的列表傳遞給函數,Alex Martelli的解決方案既不會通過複製列表來改變列表,也不會浪費內存。

+0

+1,試圖解釋概念,尤其是考慮到'初學者'和'家庭作業'標籤。 – 2009-10-04 23:37:24

0

感謝Alex馬爾泰利,你有最好的解決方案:

def theFinalAndTrulyRealProblemAsPosed(argsList): 
    items = iter(argsList) 
    output = next(items, []) * 4 
    for item in items: 
     output += item * 4 
    return output 

這是美麗和優雅。首先我們創建一個iter()的迭代器,然後我們使用next()來獲取列表中的第一個對象。然後我們在迭代列表的其餘部分時積累,我們就完成了。我們永遠不需要知道argsList中對象的類型,只要所有類型都可以使用運算符+,它們的確可以是不同的類型。這是鴨子打字。

對於目前有昨晚我很困惑,認爲你想要那個,而不是採取一個明確的名單,只是把一個或多個參數的函數。

def four_x_args(*args): 
    return theFinalAndTrulyRealProblemAsPosed(args) 

*args參數的函數告訴Python來的所有參數收集到這個功能,使一個元組出其中;那麼該元組被綁定到名稱args。您可以輕鬆製作一個列表,然後您可以使用.pop(0)方法從列表中獲取第一個項目。這花費內存和時間來建立清單,這就是爲什麼iter()解決方案如此優雅。

def four_x_args(*args): 
    argsList = list(args) # convert from tuple to list 
    output = argsList.pop(0) * 4 
    for arg in argsList: 
     output += arg * 4 
    return output 

這只是Wooble的解決方案,重寫爲使用* args。調用它的

例子:

print four_x_args(1) # prints 4 
print four_x_args(1, 2) # prints 12 
print four_x_args('a') # prints 'aaaa' 
print four_x_args('ab', 'c') # prints 'ababababcccc' 

最後,我會是惡意和抱怨,你接受的解決方案。該解決方案取決於對象的基類有一個合理的null或零,但並不是所有的類都有這個。 int()返回0str()返回''(空字符串),因此它們工作。但是怎麼樣:

class NaturalNumber(int): 
    """ 
    Exactly like an int, but only values >= 1 are possible. 
    """ 
    def __new__(cls, initial_value=1):   
     try: 
      n = int(initial_value) 
      if n < 1: 
       raise ValueError 
     except ValueError: 
      raise ValueError, "NaturalNumber() initial value must be an int() >= 1" 
     return super(NaturalNumber, cls).__new__ (cls, n) 


argList = [NaturalNumber(n) for n in xrange(1, 4)] 

print theFinalAndTrulyRealProblemAsPosed(argList) # prints correct answer: 24 

print NaturalNumber() # prints 1 
print type(argList[0])() # prints 1, same as previous line 

print multiplyItemsByFour(argList) # prints 25! 

祝你好運在你的學業,我希望你儘可能喜歡Python。

+0

@steveha,感謝您的回覆以及其他人的回覆。我尤其喜歡你和Alex的非常全面的迴應。我意識到有很多比我選擇的解決方案更好的解決方案,但我想選擇儘可能簡單明瞭的解決方案。 – Austin 2009-10-05 13:57:34