在 Python 中声明未知类型变量?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1515412/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 22:27:27  来源:igfitidea点击:

Declaring Unknown Type Variable in Python?

pythontypes

提问by Austin

I have a situation in Python(cough, homework) where I need to multiply EACH ELEMENT in a given list of objects a specified number of times and return the output of the elements. The problem is that the sample inputs given are of different types. For example, one case may input a list of strings whose elements I need to multiply while the others may be ints. So my return type needs to vary. I would like to do this without having to test what every type of object is. Is there a way to do this? I know in C# i could just use "var" but I don't know if such a thing exists in Python?

我在 Python(咳嗽,作业)中有一种情况,我需要将给定对象列表中的每个元素乘以指定次数并返回元素的输出。问题是给出的样本输入是不同类型的。例如,一种情况可能会输入一个字符串列表,我需要将其元素相乘,而其他情况可能是整数。所以我的返回类型需要变化。我想这样做而不必测试每种类型的对象是什么。有没有办法做到这一点?我知道在 C# 中我可以只使用“var”,但我不知道 Python 中是否存在这样的东西?

I realize that variables don't have to be declared, but in this case I can't see any way around it. Here's the function I made:

我意识到不必声明变量,但在这种情况下,我看不到任何解决方法。这是我做的功能:

def multiplyItemsByFour(argsList):

output = ????

for arg in argsList:
        output += arg * 4

return output

See how I need to add to the output variable. If I just try to take away the output assignment on the first line, I get an error that the variable was not defined. But if I assign it a 0 or a "" for an empty string, an exception could be thrown since you can't add 3 to a string or "a" to an integer, etc...

看看我需要如何添加到输出变量。如果我只是尝试取消第一行的输出分配,则会收到未定义变量的错误。但是,如果我为空字符串分配 0 或“”,则可能会引发异常,因为您无法将 3 添加到字符串或将“a”添加到整数等...

Here are some sample inputs and outputs:

以下是一些示例输入和输出:

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

Thanks!

谢谢!

采纳答案by Don O'Donnell

Very easy in Python. You need to get the type of the data in your list - use the type() function on the first item - type(argsList[0]). Then to initialize output (where you now have ????) you need the 'zero' or nul value for that type. So just as int() or float() or str() returns the zero or nul for their type so to will type(argsList[0])() return the zero or nul value for whatever type you have in your list.

在 Python 中非常容易。您需要获取列表中数据的类型 - 在第一项上使用 type() 函数 - type(argsList[0])。然后要初始化输出(您现在拥有 ??),您需要该类型的“零”或空值。因此,就像 int() 或 float() 或 str() 为其类型返回零或 nul 一样, type(argsList[0])() 将为您列表中的任何类型返回零或 nul 值。

So, here is your function with one minor modification:

因此,这是您的功能,只需稍作修改:

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

Works with:: argsList = [1, 2, 3, 4]or [1.0, 2.0, 3.0, 4.0]or "abcdef"... etc,

与:: argsList = [1, 2, 3, 4]or [1.0, 2.0, 3.0, 4.0]or "abcdef"... 等一起使用,

回答by Alex Martelli

def fivetimes(anylist):
  return anylist * 5

As you see, if you're given a list argument, there's no need for any assignment whatsoever in order to "multiply it a given number of times and return the output". You talk about a givenlist; how is it givento you, if not (the most natural way) as an argument to your function? Not that it matters much -- if it's a global variable, a property of the object that's your argument, and so forth, this still doesn't necessitate any assignment.

如您所见,如果给定了一个列表参数,则无需进行任何赋值以“将其乘以给定的次数并返回输出”。你谈论一个给定的清单;如果不是(最自然的方式)作为函数的参数,它是如何提供给你的?并不是说它很重要——如果它是一个全局变量,一个作为你参数的对象的属性,等等,这仍然不需要任何赋值。

If you were "homeworkically" forbidden from using the *operator of lists, and just required to implement it yourself, this would require assignment, but no declaration:

如果您“作业上”被禁止使用*列表运算符,而只需要自己实现它,这将需要赋值,但不需要声明:

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

You can simply make the empty list "magicaly appear": there's no need to "declare" it as being anything whatsoever, it's an empty list and the Python compiler knows it as well as you or any reader of your code does. Binding it to the name outputlistdoesn't require you to perform any special ritual either, just the binding (aka assignment) itself: names don't have types, only objectshave types... that's Python!-)

您可以简单地使空列表“神奇地出现”:无需将其“声明”为任何内容,它是一个空列表,Python 编译器和您或您的代码的任何读者一样了解它。将它绑定到名称outputlist也不需要您执行任何特殊的仪式,只需绑定(也称为赋值)本身:名称没有类型,只有对象有类型......那是 Python!-)

Edit: OP now says output must not be a list, but rather int, float, or maybe string, and he is given no indication of what. I've asked for clarification -- multiplying a list ALWAYS returns a list, so clearly he must mean something different from what he originally said, that he had to multiply a list. Meanwhile, here's another attempt at mind-reading. Perhaps he must return a list where EACH ITEM of the input list is multiplied by the same factor (whether that item is an int, float, string, list, ...). Well then:

编辑:OP 现在说输出不能是列表,而是整数、浮点数或字符串,并且他没有给出任何指示。我已经要求澄清 - 乘以一个列表总是会返回一个列表,所以很明显他的意思肯定与他最初所说的有所不同,他必须乘以一个列表。与此同时,这是另一种读心术的尝试。也许他必须返回一个列表,其中输入列表的 EACH ITEM 乘以相同的因子(无论该项目是整数、浮点数、字符串、列表……)。好吧:

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

Look ma, no hands^H^H^H^H^H assignment. (This is known as a "list comprehension", btw).

看,没有手^H^H^H^H^H 分配。(这被称为“列表理解”,顺便说一句)。

Or maybe (unlikely, but my mind-reading hat may be suffering interference from my tinfoil hat, will need to go to the mad hatter's shop to have them tuned) he needs to (say) multiply each list item as ifthey were the same type as the first item, but return them as their original type, so that for example

或者(不太可能,但我的读心帽可能会受到锡箔帽的干扰,需要去疯帽子店调整它们)他需要(比如说)将每个列表项相乘,就好像它们是相同的type 作为第一项,但将它们作为原始类型返回,例如

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

Even this highly-mystical spec COULD be accomodated...:

即使是这个高度神秘的规格也可以适应......:

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

...though I very much doubt it's the spec actually encoded in the mysterious runes of that homework assignment. Just about ANY precise spec can be either implemented or proven to be likely impossible as stated (by requiring you to solve the Halting Problem or demanding that P==NP, say;-). That may take some work ("prove the 4-color theorem", for example;-)... but still less than it takes to magically divine what the actual spec IS, from a collection of mutually contradictory observations, no examples, etc. Though in our daily work as software developer (ah for the good old times when all we had to face was homework!-) we DO meet a lot of such cases of course (and have to solve them to earn our daily bread;-).

...虽然我非常怀疑它实际上是编码在那个家庭作业的神秘符文中的规范。几乎任何精确的规范都可以实现或证明可能是不可能的(通过要求您解决停机问题或要求 P==NP,例如;-)。这可能需要一些工作(例如,“证明 4 色定理”;-)...但仍然少于从相互矛盾的观察集合中神奇地预测实际规范是什么,没有示例等. 虽然在我们作为软件开发人员的日常工作中(啊,在过去的美好时光里,我们只需要面对家庭作业!-)我们当然会遇到很多这样的情况(并且必须解决它们才能赚取日常收入;- )。

EditEdit: finally seeing a precise spec I point out I already implemented that one, anyway, here it goes again:

EditEdit:终于看到了一个精确的规范,我指出我已经实现了那个规范,无论如何,它再次出现:

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

EditEditEdit: finally/finally seeing a MORE precise spec, with (luxury!-) examples:

EditEditEdit:终于/终于看到了更精确的规范,带有(豪华!-)示例

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

So then what's wanted it the summation(and you can't use sumas it wouldn't work on strings) of the items in the input list, each multiplied by four. My preferred solution:

那么什么是输入列表中项目的总和(并且您不能使用,sum因为它不适用于字符串),每个项目乘以四。我的首选解决方案:

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

If you're forbidden from using some of these constructs, such as built-ins itemsand iter, there are many other possibilities (slightly inferior ones) such as:

如果您被禁止使用其中一些构造,例如内置itemsiter,还有许多其他可能性(稍差一些),例如:

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

For an empty argsList, the first version returns [], the second one returns None-- not sure what you're supposed to do in that corner case anyway.

对于空的argsList,第一个版本返回[],第二个版本返回None- 不确定在那个极端情况下你应该做什么。

回答by steveha

My guess is that the purpose of your homework is to expose you to "duck typing". The basic idea is that you don't worry about the types too much, you just worry about whether the behaviorswork correctly. A classic example:

我的猜测是你的家庭作业的目的是让你接触“鸭子打字”。基本思想是您不必过多担心类型,您只担心行为是否正常工作。一个经典的例子:

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]

Notice that when you defa function in Python, you don't declare a return type anywhere. It is perfectly okay for the same function to return different types based on its arguments. It's considered a virtue, even; consider that in Python we only need one definition of add_two()and we can add integers, add floats, concatenate strings, and join lists with it. Statically typed languages would require multiple implementations, unless they had an escape such as variant, but Python is dynamically typed. (Python is strongly typed, but dynamically typed. Some will tell you Python is weakly typed, but it isn't. In a weakly typed language such as JavaScript, the expression 1 + "1"will give you a result of 2; in Python this expression just raises a TypeErrorexception.)

请注意,当您def在 Python 中创建函数时,您不会在任何地方声明返回类型。同一个函数根据其参数返回不同的类型是完全可以的。它甚至被认为是一种美德;考虑到在 Python 中我们只需要一个定义,add_two()我们可以添加整数、添加浮点数、连接字符串和连接列表。静态类型语言需要多个实现,除非它们有诸如 之类的转义符variant,但 Python 是动态类型的。(Python 是强类型的,但是是动态类型的。有些人会告诉你 Python 是弱类型的,但事实并非如此。在弱类型语言(如 JavaScript)中,表达式1 + "1"会给你 2 的结果;在 Python 中,这个表达式只是引发一个TypeError例外。)

It is considered very poor style to try to test the arguments to figure out their types, and then do things based on the types. If you need to make your code robust, you can always use a tryblock:

尝试测试参数以找出它们的类型,然后根据类型做事被认为是非常糟糕的风格。如果你需要让你的代码健壮,你总是可以使用一个try块:

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

See also the Wikipedia page on duck typing.

另请参阅有关鸭子打字的维基百科页面。

回答by John Y

Are you sure this is for Python beginners? To me, the cleanest way to do this is with reduce() and lambda, both of which are not typical beginner tools, and sometimes discouraged even for experienced Python programmers:

你确定这是给 Python 初学者的吗?对我来说,最简洁的方法是使用 reduce() 和 lambda,这两个工具都不是典型的初学者工具,有时甚至对于有经验的 Python 程序员也不鼓励:

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

Like Alex Martelli, I've thrown in a quick test for an empty list at the beginning which returns None. Note that if you are using Python 3, you must import functools to use reduce().

像 Alex Martelli 一样,我在开头对一个空列表进行了快速测试,该列表返回 None。请注意,如果您使用的是 Python 3,则必须导入 functools 才能使用 reduce()。

Essentially, the reduce(lambda...) solution is very similar to the other suggestions to set up an accumulator using the first input item, and then processing the rest of the input items; but is simply more concise.

本质上,reduce(lambda...) 解决方案与使用第一个输入项设置累加器,然后处理其余输入项的其他建议非常相似;但更简洁。

回答by nielsm

Python is dynamically typed, you don't need to declare the type of a variable, because a variable doesn't have a type, only values do. (Any variable can store any value, a value never changes its type during its lifetime.)

Python 是动态类型的,你不需要声明变量的类型,因为变量没有类型,只有值才有。(任何变量都可以存储任何值,值在其生命周期内永远不会改变其类型。)

def do_something(x):
    return x * 5

This will work for any xyou pass to it, the actual result depending on what type the value in xhas. If xcontains a number it will just do regular multiplication, if it contains a string the string will be repeated five times in a row, for lists and such it will repeat the list five times, and so on. For custom types (classes) it depends on whether the class has an operation defined for the multiplication operator.

这将适用于x您传递给它的任何内容,实际结果取决于值的类型x。如果x包含一个数字,它将只进行常规乘法,如果它包含一个字符串,则该字符串将连续重复五次,对于列表等,它将重复列表五次,依此类推。对于自定义类型(类),它取决于该类是否具有为乘法运算符定义的运算。

回答by steveha

You gave these sample inputs and outputs:

您提供了这些示例输入和输出:

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

输入:('a','b') 输出:'aaaabbbb' 输入:(2,3,4) 输出:36

I don't want to write the solution to your homework for you, but I do want to steer you in the correct direction. But I'm still not sure I understand what your problem is, because the problem as I understand it seems a bit difficult for an intro to Python class.

我不想为你写作业的解决方案,但我确实想引导你朝着正确的方向前进。但是我仍然不确定我是否理解您的问题,因为据我所知,对于 Python 类的介绍来说,这个问题似乎有点困难。

The most straightforward way to solve this requires that the arguments be passed in a list. Then, you can look at the first item in the list, and work from that. Here is a function that requires the caller to pass in a list of two items:

解决这个问题的最直接的方法是在列表中传递参数。然后,您可以查看列表中的第一项,并以此为基础进行操作。这是一个函数,它要求调用者传入包含两个项目的列表:

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

Now, how can we make this extend past two items? Well, in your sample code you weren't sure what to assign to your variable output. How about assigning lst[0]? Then it always has the correct type. Then you could loop over all the other elements in lst and accumulate to your output variable using += as you wrote. If you don't know how to loop over a list of items but skip the first thing in the list, Google search for "python list slice".

现在,我们怎样才能使这个扩展超过两个项目?好吧,在您的示例代码中,您不确定将什么分配给变量输出。分配 lst[0] 怎么样?那么它总是具有正确的类型。然后,您可以循环遍历 lst 中的所有其他元素,并在编写时使用 += 累加到您的输出变量。如果您不知道如何遍历项目列表但跳过列表中的第一件事,请在 Google 上搜索“python list slice”。

Now, how can we make this not require the user to pack up everything into a list, but just call the function? What we really want is some way to accept whatever arguments the user wants to pass to the function, and make a list out of them. Perhaps there is special syntax for declaring a function where you tell Python you just want the arguments bundled up into a list. You might check a good tutorialand see what it says about how to define a function.

现在,我们如何使这不需要用户将所有内容打包成一个列表,而只需调用该函数?我们真正想要的是某种方式来接受用户想要传递给函数的任何参数,并从中列出一个列表。也许有一种特殊的语法来声明一个函数,你告诉 Python 你只想要将参数捆绑到一个列表中。你可以查看一个很好的教程,看看它是如何定义函数的。

Now that we have covered (very generally) how to accumulate an answer using +=, let's consider other ways to accumulate an answer. If you know how to use a list comprehension, you could use one of those to return a new list based on the argument list, with the multiply performed on each argument; you could then somehow reduce the list down to a single item and return it. Python 2.3 and newer have a built-in function called sum()and you might want to read up on that. [EDIT: Oh drat, sum()only works on numbers. See note added at end.]

现在我们已经(非常一般地)介绍了如何使用 += 累积答案,让我们考虑其他累积答案的方法。如果您知道如何使用列表推导式,您可以使用其中之一返回基于参数列表的新列表,并对每个参数执行乘法运算;然后你可以以某种方式将列表减少到单个项目并返回它。Python 2.3 和更新版本有一个内置函数sum(),你可能想阅读它。[编辑:哦,天哪,sum()只适用于数字。请参阅末尾添加的注释。]

I hope this helps. If you are still very confused, I suggest you contact your teacher and ask for clarification. Good luck.

我希望这有帮助。如果你仍然很困惑,我建议你联系你的老师并要求澄清。祝你好运。

P.S. Python 2.x have a built-in function called reduce()and it is possible to implement sum()using reduce(). However, the creator of Python thinks it is better to just use sum()and in fact he removed reduce()from Python 3.0 (well, he moved it into a module called functools).

PS Python 2.x 有一个内置函数reduce(),可以sum()使用reduce(). 然而,Python 的创建者认为直接使用更好sum(),事实上他reduce()从 Python 3.0 中删除了(好吧,他将它移到了一个名为 的模块中functools)。

P.P.S. If you get the list comprehension working, here's one more thing to think about. If you use a list comprehension and then pass the result to sum(), you build a list to be used once and then discarded. Wouldn't it be neat if we could get the result, but instead of building the whole list and then discarding it we could just have the sum()function consume the list items as fast as they are generated? You might want to read this: Generator Expressions vs. List Comprehension

PPS 如果您使列表理解有效,那么还有一件事需要考虑。如果您使用列表推导式,然后将结果传递给sum(),则您构建的列表将被使用一次然后被丢弃。如果我们能得到结果不是很好,而是不是构建整个列表然后丢弃它,我们可以让sum()函数在列表项生成时尽快使用它们?您可能想阅读以下内容:生成器表达式与列表理解

EDIT: Oh drat, I assumed that Python's sum()builtin would use duck typing. Actually it is documented to work on numbers, only. I'm disappointed! I'll have to search and see if there were any discussions about that, and see why they did it the way they did; they probably had good reasons. Meanwhile, you might as well use your += solution. Sorry about that.

编辑:哦,天哪,我认为 Python 的sum()内置函数会使用鸭子类型。实际上,它仅适用于数字。我很失望!我必须搜索一下,看看是否有任何讨论,看看他们为什么这样做;他们可能有充分的理由。同时,您也可以使用您的 += 解决方案。对于那个很抱歉。

EDIT: Okay, reading through other answers, I now notice two ways suggested for peeling off the first element in the list.

编辑:好的,阅读其他答案,我现在注意到建议剥离列表中的第一个元素的两种方法。

For simplicity, because you seem like a Python beginner, I suggested simply using output = lst[0]and then using list slicing to skip past the first item in the list. However, Wooble in his answer suggested using output = lst.pop(0)which is a very clean solution: it gets the zeroth thing on the list, and then you can just loop over the list and you automatically skip the zeroth thing. However, this "mutates" the list! It's better if a function like this does not have "side effects" such as modifying the list passed to it. (Unless the list is a special list made just for that function call, such as a *argslist.) Another way would be to use the "list slice" trick to make a copy of the list that has the first item removed. Alex Martelli provided an example of how to make an "iterator" using a Python feature called iter(), and then using iterator to get the "next" thing. Since the iterator hasn't been used yet, the next thing is the zeroth thing in the list. That's not really a beginner solution but it is the most elegant way to do this in Python; you could pass a really huge list to the function, and Alex Martelli's solution will neither mutate the list nor waste memory by making a copy of the list.

为简单起见,因为您看起来像一个 Python 初学者,我建议简单地使用output = lst[0]然后使用列表切片跳过列表中的第一项。但是,Wooble 在他的回答中建议使用output = lst.pop(0)which 是一个非常干净的解决方案:它获取列表中的第零个东西,然后您可以循环遍历列表并自动跳过第零个东西。然而,这“改变”了列表!如果像这样的函数没有“副作用”,例如修改传递给它的列表,那就更好了。(除非列表是专门为该函数调用制作的特殊列表,例如*args列表。)另一种方法是使用“列表切片”技巧来制作删除第一项的列表的副本。Alex Martelli 提供了一个如何制作“迭代器”的例子iter(),然后使用迭代器来获得“下一个”的东西。由于尚未使用迭代器,接下来是列表中的第零个。这不是真正的初学者解决方案,但它是在 Python 中执行此操作的最优雅的方法;您可以向函数传递一个非常大的列表,Alex Martelli 的解决方案既不会改变列表,也不会通过复制列表来浪费内存。

回答by Wooble

You don't need to declare variable types in python; a variable has the type of whatever's assigned to it.

你不需要在python中声明变量类型;变量具有分配给它的任何类型。

EDIT:

编辑:

To solve the re-stated problem, try this:

要解决重新陈述的问题,请尝试以下操作:

def multiplyItemsByFour(argsList):

output = argsList.pop(0) * 4

for arg in argsList:
        output += arg * 4

return output

(This is probably not the most pythonic way of doing this, but it should at least start off your output variable as the right type, assuming the whole list is of the same type)

(这可能不是最 Pythonic 的方法,但它至少应该从你的输出变量作为正确的类型开始,假设整个列表是相同的类型)

回答by foosion

No need to test the objects, just multiply away!

无需测试对象,只需乘以!

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

all just work

一切正常

回答by stonemetal

Try this:

试试这个:

def timesfourlist(list):
 nextstep = map(times_four, list)
 sum(nextstep)

map performs the function passed in on each element of the list(returning a new list) and then sum does the += on the list.

map 在列表的每个元素上执行传入的函数(返回一个新列表),然后 sum 在列表上执行 += 。

回答by Nikwin

If you just want to fill in the blank in your code, you could try setting object=arglist[0].__class__()to give it the zero equivalent value of that class.

如果您只想填充代码中的空白,您可以尝试设置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

This will crash if the list is empty, but you can check for that case at the beginning of the function and return whatever you feel appropriate.

如果列表为空,这将崩溃,但您可以在函数的开头检查这种情况并返回您认为合适的任何内容。