简体   繁体   English

如何创建具有指定特征的类?

[英]How do I create a class with the specified characteristics?

What I want to do is to create a class that I will call a Cluster that I can use to store representations of multivariable data points.我想要做的是创建一个类,我将称之为Cluster ,我可以用它来存储多变量数据点的表示。 Like a bunch of people's heights, weights, and ages.就像一群人的身高、体重和年龄。 I want to make it so when I create an instance of Cluster , it returns an empty dictionary.我想这样做,当我创建一个Cluster实例时,它返回一个空字典。 I then want to be able to add key value pairs.然后我希望能够添加键值对。 I want each value paired with each key to only be a list.我希望与每个键配对的每个值都只是一个列表。 I want each list to only contain only 1 data type.我希望每个列表只包含 1 种数据类型。

However, they don't have to be the same data type for every list.但是,它们不必对每个列表都具有相同的数据类型。 What I mean is that one list can only consists of integers, and the other list is only full of strings.我的意思是,一个列表只能包含整数,而另一个列表只能包含字符串。 I even allow a list of tuples or lists or dictionaries.我什至允许使用元组列表或列表或字典。 They don't even have to have the same data type for each value in itself.它们甚至不必为每个值本身具有相同的数据类型。 But, the overall list must then contain all dictionaries, tuples, etc.但是,整个列表必须包含所有字典、元组等。

Example of a Cluster : Cluster示例:

{'Hobbies': [(3, 's', {'name': 'Sam'}), (4, 5), (), (True)], 'Weights': [1, 34, 3, 90]}

Notice how the above 'Hobbies' value pair is a list of only tuples and the 'Weights' value pair is a list of only integers.注意上面的“爱好”值对是一个只有元组的列表,而“权重”值对是一个只有整数的列表。 This is what I mean by what I am trying to say above.这就是我上面想说的意思。

I created a function that generates what a Cluster full of values should look like, but I want it to be a class.我创建了一个函数来生成一个充满值的Cluster应该是什么样子,但我希望它是一个类。 It gives you what I want to happen, but I want make a class , not a function that generates it.它给了你我想要发生的事情,但我想要一个class ,而不是一个生成它的函数。 Other methods such as getting the length of the Cluster I can figure out, I just want everything that I said above to be true.其他方法,例如获取我可以计算出的Cluster的长度,我只是希望我上面说的一切都是真的。

from random import randint


def create_cluster(a, b, c, *d):
    cluster = {}
    for key in d:
        point = []
        for integer in range(0, a):
            point.append(randint(b, c))
        cluster[key] = point
    return cluster


print(create_cluster(4, 2, 9, 'Height', 'Weight', 'Age'))

Output:输出:

{'Height': [5, 3, 3, 6], 'Weight': [7, 3, 5, 7], 'Age': [9, 5, 3, 6]}

As Code-Apprentice mentions, there is no mechanism by which python enforces type checking in the sense that it will stop you from compiling and running the code.正如 Code-Apprentice 所提到的,python 没有强制执行类型检查的机制,因为它会阻止您编译和运行代码。 As of version 3.5, however, Python allows you to implement a soft type checking - you can read about it here .但是,从 3.5 版开始,Python 允许您实现软类型检查 - 您可以在此处阅读有关它的信息 What this means is that Python now offers you a way too check to see if your code is passing illegal values to functions/classes/variables etc.这意味着 Python 现在为您提供了一种方法来检查您的代码是否将非法值传递给函数/类/变量等。

Here's how it works:这是它的工作原理:

from typing import Dict, List, Any, Tuple, Union
from random import randint

class Cluster:
    def __init__(self):
        self.data: Dict[str, List[Any]] = {}

    def create_cluster(self, a, b, c, *d):
        for key in d:
            point = []
            for integer in range(0, a):
                point.append(randint(b, c))
            self.data[key] = point

clust = Cluster()
clust.create_cluster(4, 2, 9, 'Height', 'Weight', 'Age')
print(clust.data)

Edit: for your example specifically, you'd want something like:编辑:对于您的示例,您需要如下内容:

self.data: Dict[str, List[Union[Tuple, int]] = {}

Union is a type that indicates a wildcard of specified possibilities, so the dictionary value can be a list containing either tuples or ints. Union 是指示指定可能性的通配符的类型,因此字典值可以是包含元组或整数的列表。 I guess if you wanted to further restrict the data types inside the tuples, you could do:我想如果你想进一步限制元组内的数据类型,你可以这样做:

self.data: Dict[str, List[Union[Tuple[Union[int, str]], int]] = {}

Next, you need mypy installed .接下来,您需要安装 mypy Mypy has to be called separately from a terminal on your script, but it will go through the code and perform a type check - that is, it will alert you to any instances where you have declared illegal variables in your class. Mypy 必须与脚本中的终端分开调用,但它会遍历代码并执行类型检查 - 也就是说,它会提醒您在类中声明非法变量的任何实例。

Alternatively, you could perform a series of in-code catches involving:或者,您可以执行一系列代码内捕获,包括:

if type(data['Weight'][0]) != whatever:
    raise("You're putting the wrong type of variable in")

But mypy seems like a better solution in the longer term.但从长远来看,mypy 似乎是一个更好的解决方案。 It'll save you from having to wait for your code to execute, run, and fail in a predictable spot.它将使您不必等待代码在可预测的位置执行、运行和失败。

Feedback and corrections welcome.欢迎反馈和更正。

If I'm understanding what you need, we can actually make a dict object that will type check for you!如果我了解您的需求,我们实际上可以制作一个 dict 对象来为您进行类型检查! No imports needed.不需要进口。

We just have to subclass the dict class, and override the functions for adding items to the dictionary, so we can type check before allowing any additions.我们只需要继承 dict 类,并覆盖将项目添加到字典的函数,这样我们就可以在允许任何添加之前键入检查。

Here is the code below.这是下面的代码。

class ClusterDict(dict):
    key_type = str  # we want all of our keys to be str type
    value_type = list  # same for our value as a list

    # lets override the function for dictionary assignment so we can type check before we add to our dictionary
    def __setitem__(self, key, value):
        self.type_check_and_add(key, value)

    # Lets override update as well
    def update(self, **kwargs) -> None:
        for key, value in kwargs.items():
            self.type_check_and_add(key, value)

    def type_check_and_add(self, key: str, value: list) -> None:
        assert type(key) == self.key_type, f"Expected {self.key_type} for key, got {type(key)} instead."
        if type(value) is not list:
            value = [value]  # Make it a list if its isn't, remove this if you know it will always come as a list, even if its a single entry, like [5], or [(2, 6)]
        assert type(value) == self.value_type, f"Expected {self.value_type} for key, got {type(value)} instead."
        val_type = type(value[0])  # type of first item in list, lets make sure they all match this one
        for val in value:
            assert type(val) == val_type, f"Items do not have matching types for key {key}."
        super().__setitem__(key, value)  # this then passes assignment as usual to the base class dict

Lets do some tests now!现在让我们做一些测试!

if __name__ == '__main__':
    clust = ClusterDict()
    input_data = {
        'Height': [4, 3, 5],
        'Age': [(4, 9), (4, 6, 8)]
    }
    clust.update(**input_data)
    print(clust)
{'Height': [4, 3, 5], 'Age': [(4, 9), (4, 6, 8)]}

Looks good so far, we can add whole dictionaries using update as usual到目前为止看起来不错,我们可以像往常一样使用更新添加整个字典

    input_data = {'Weights': [1, 34, 3, 90]}
    clust.update(**input_data)
    print(clust)
{'Height': [4, 3, 5], 'Age': [(4, 9), (4, 6, 8)], 'Weights': [1, 34, 3, 90]}

Or just one entry at a time.或者一次只输入一个。

Lets try the usual way, dict[key] = value让我们试试通常的方法,dict[key] = value

    clust['Hobbies'] = [(3, 's', {'name': 'Sam'}), (4, 5), (), (True,)]
    print(clust)
{'Height': [4, 3, 5], 'Age': [(4, 9), (4, 6, 8)], 'Weights': [1, 34, 3, 90], 'Hobbies': [(3, 's', {'name': 'Sam'}), (4, 5), (), (True,)]}

Looking good.看起来不错。 But now lets try adding a list with types that don't match.但是现在让我们尝试添加一个类型不匹配的列表。

    clust['My Favorite Number'] = [7, '7', (1, 1, 1, 1, 1, 1, 1)]
    print(clust)
    assert type(val) == val_type, f"Items do not have matching types for key {key}."
AssertionError: Items do not have matching types for key My Favorite Number.

Which throws an AssertionError and prevents us from doing so, like we wanted.这会抛出一个 AssertionError 并阻止我们这样做,就像我们想要的那样。

Bonus though, because we subclassed dict, we get all of its methods for free!尽管如此,因为我们对 dict 进行了子类化,所以我们免费获得了它的所有方法!

>>>len(clust)
4

for k, v in clust.items():
...     print(k, v)
...     
Height [4, 3, 5]
Age [(4, 9), (4, 6, 8)]
Weights [1, 34, 3, 90]
Hobbies [(3, 's', {'name': 'Sam'}), (4, 5), (), (True,)]

Hopefully this is what you were looking for and it helps!希望这就是您要找的东西,它会有所帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM