【问题标题】:How do I store an object in a dynamically generated variable?如何将对象存储在动态生成的变量中?
【发布时间】:2019-07-03 12:10:14
【问题描述】:

我有一个包含一系列客户的文本文件。 每条线路都有不同的客户。 每个客户端都有一个 ID、一个用户名和一个密码。

我想创建一个“客户端”类,并在该类中循环生成对象。 每个对象都有一个用户名和一个密码,并将存储在一个包含客户 ID 的变量中。 客户端 1 将存储在“client_1”中,客户端 2 将存储在“client_2”中,等等。

我创建了方法“read()”,它打开文本文件,如果有空行则中断,并检索每个客户端(每一行)的 ID、用户名和密码。

我想不通的是如何做到这一点,以便当客户端的 ID 为“1”时,我为该客户端创建一个对象并将其存储在变量“client_1”中。 当客户端的ID为“2”时,我将客户端的2对象存储在变量“client_2”中,以此类推。

但我想自动执行此操作,而不是拥有 9000 个客户端并且必须自己创建 9000 个变量。

谢谢

class Client:

    def __init__(self, username, password):
        self.username = username
        self.password = password

    def read(self):
        clients = []
        with open("Clients.txt", "r") as file:
            lines = file.readlines()
            for line in lines:
                if not line:
                    break
                else:
                    client = line.split(" | ")
                    client_id = client[0]
                    #How do I create the variable "client_client[0]"?
                    username = client[1]
                    pre_password = client[2]
                    password = pre_password.strip("\n")
                    #client_client[0] = Client(username, password)
                    clients.append(#client_client[0])
            return clients

我的文本文件(ID、用户名、密码 - 从左到右):

1 | admin | Z9?zzz
2 | John | J1!jjj
3 | Steve | S1!sss

另外,如果我在 read() 中使用“用户名”和“密码”变量,而我已经在 def init 中使用了它们,是否会出现问题?

谢谢

【问题讨论】:

  • 为什么不列出客户端对象?
  • @user2229219 这不是我在做什么吗?我创建了空列表“客户”,并在创建每个对象后,将其附加到该列表中。在“read()”结束时,我返回列表。你能详细说明一下吗?谢谢。
  • read 函数看起来不错,您对列表的使用似乎是显而易见的正确方法。看我的回答。

标签: python python-3.x class oop object


【解决方案1】:

建议

  • 在您的循环中,您使用的是break。不要那样做,你要使用的是continue,它将跳过这个迭代而不是让你摆脱它。

  • 您的密码仅使用了strip('\n')。您应该对所有项目执行此操作(以确保它们都是统一的)。但是您只在密码情况下使用strip('\n') 是正确的,因为它是唯一具有\n 的情况。不要将参数放入strip(),它会处理所有空格、制表符和其他\n\r 等。

  • 您应该将类​​的self 参数视为存在于其中的box。这是“环境”,您基本上可以在课堂上的任何地方访问。而且,如果您在self 中创建了一些东西,例如self.client,它将与名为client 的单个变量不同。您可能想要在这里做的是将您刚刚阅读的客户列表分配给self,例如self.client_list = self.read()

关于您的计划

您需要做的不是创建与用户一样多的变量。但是您的哲学是对的,您希望将它们存储在一个地方。这就是你所做的。现在,您的程序的意义对我们来说仍然是模糊的。但你可能想要做的是:

  1. 拥有一个数据库可以在其中了解商品的排序方式。您知道,在您的 users_list 的每个元素中,您的第一项是 id,第二项是 name,第三项是 password

  2. 根据这个数据库进行操作。

    • 您想“加载”一个客户,检查他是否存在于您的数据库中,并将他输入的密码与您链接的密码相匹配!
    • 要删除一个吗?
    • 为已登录的用户订购冰淇淋?

【讨论】:

    【解决方案2】:

    不要动态创建变量!而是使用 Python 的内置字典对象,它允许您通过键查找值。

    class Client:
    
        def __init__(self, username, password):
            self.username = username
            self.password = password
    
    def read(file):
        clients = {}
        for line in file:
            if not line:
                continue  # allows blank lines anywhere
            else:
                id, name, password = line.split(" | ")
                password = password.strip("\n")
                clients[id] = Client(name, password)
        return clients
    
    if __name__ == '__main__':
        data = """\
    1 | admin | Z9?zzz
    2 | John | J1!jjj
    3 | Steve | S1!sss
    """
        from io import StringIO
        with StringIO(data) as file:
            clients = read(file)
        for id, client in clients.items():
            print(id, client.username, client.password)
    

    read 函数作为类的方法有点令人困惑,因为调用它需要您创建一个Client 实例才能调用它。另一种方法是将其重铸为classmethod,但这会使事情过于复杂,因此它作为一个简单的函数更有意义。它不是返回一个列表,而是返回一个Clients 的字典,每个字典都键入其各自的id

    我已经稍微简化了处理(尽管仍然没有错误处理),并使循环对空行更加健壮。

    我还添加了一些测试代码,以允许您验证客户端是否已根据您的测试数据正确创建,并根据您的选择使您的类和函数importable。将 with StringIO(data) as file: 替换为 with open("Clients.txt") as file: 以使用真实数据文件。

    【讨论】:

      【解决方案3】:

      您已经拥有的客户列表有什么问题?您可以通过clients[0]clients[1] 等方式访问客户端。该列表是任意多个变量的抽象。列表索引为 0,因此第一个元素的索引为 0。这可能会令人困惑,尤其是因为某些语言(如 R、FORTRAN 或 Wolfram 语言)是 1 索引的。我不认为这是一个根本问题,你只需要弄清楚它。如果它真的让您感到困扰,您可以使用带有数字索引的 dict,并将您想要的任何索引映射到客户。

      另外,我会将read_clients 设为免费功能。除了 Client 类的公共 API 之外,它不使用任何东西来运行。因此它不应该是成员函数。但是,如果您想在该类中使用它,请至少将其设为 @staticmethod,因为它与特定的 Client 无关。

      我对公共 API 的意思是:您编写的每个类都有公共方法和私有方法。在 Python 中没有访问说明符,但约定是以下划线 (_) 开头的方法不会在外部使用。带有两个下划线的那些(如__init__)也不能直接调用,而是由语法糖调用。你想要有重点的方法(SRP),所以尽可能少的公共函数。还要考虑一下:假设有人想使用您的Client 类来读取具有用户名和密码的不同文件格式。该人必须修改您的代码才能添加另一个read 方法。但是,如果 read_clients 函数是外部函数并且只使用了 Client 类的 __init__,那么有人可以在某处添加一个新的免费函数。这是OCP

      Client 可能只是一个collections.NamedTuple。像这样:

      import collections
      
      Client = collections.namedtuple('Client', ['username', 'password'])
      
      def read_clients(filename):
          clients = []
      
          # open file
              # loop over all lines in the list
                  # Parse the username and password.
                  username = # …
                  password = # …
                  client = Client(username, password)
                  clients.append(client)
      
          return clients
      

      您不必自己定义类Client,所有Client 对象(例如client)都将具有client.usernameclient.password 属性。

      使用passwordusername 没有问题,因为__init__ 的参数在不同的范围内。您的班级成员只能通过self. 访问,所以这也不是问题。

      如果您真的想要动态创建变量,有办法做到这一点,see here。但是你又想抽象出实际的客户数量,这就是列表的用途。

      【讨论】:

      • 如果我使用列表,我可以使用类方法吗?我不知道。此外,客户端 1 将位于客户端 [0] 中,客户端 2 将位于客户端 [1] 中。这不会带来问题吗?我也在谷歌搜索“Python 公共 API”和“静态方法”,因为老实说我不知道​​那是什么。我也不明白你所说的 collections.namedtuple 是什么意思。我还有很多东西要学,谢谢!
      • @AntónioGonçalves:我已经扩展了我的答案,并试图解决你评论中的所有问题。
      猜你喜欢
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-08
      • 2021-03-10
      • 2012-02-05
      相关资源
      最近更新 更多