[英]How do I store an object in a dynamically generated variable?
我有一个带有一系列客户端的文本文件。 每行都有一个不同的客户端。 每个客户端都有一个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
另外,如果我已经在def init中使用了“ username”和“ password”变量,是否在read()中使用了问题?
谢谢
在循环中,您正在使用break
。 不要那样做,您要使用的是continue
,它将跳过此迭代而不是使您脱离迭代。
您仅在密码上使用strip('\\n')
。 您应该对所有物品都这样做(以确保它们都统一)。 但是您只应在密码情况下使用strip('\\n')
是正确的,因为它是唯一具有\\n
的密码。 不要将参数放入strip()
,它将处理所有空格,制表符以及其他\\n
, \\r
等。
您应该将类的self
参数视为位于其中的box
。 这是您基本上可以在班级各处访问的“环境” 。 并且,如果您在self
内部创建某些内容(例如self.client
,则该名称将与名为client
的单个变量不同。 您在这里可能想要做的就是将刚刚读取的客户列表分配给self
,例如self.client_list = self.read()
。
您需要做的是创建的变量不如用户那么多 。 但是您的哲学正确,您想将它们存储在一个地方。 那就是你所做的。 现在,您的程序的要点对我们还是很模糊。 但是您可能想要做的是:
有一个数据库 , 您可以在其中了解如何订购商品。 您知道,在users_list的每个元素中,都有第一项是id
,第二项是name
,第三项是password
。
根据此数据库进行操作。
您已经拥有的客户列表有什么问题? 您可以作为clients[0]
, clients[1]
等访问客户clients[0]
。 该列表是任意多个变量的抽象。 列表的索引为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.username
和client.password
。
使用password
和username
不是问题,因为__init__
的参数在不同的范围内。 您班上的成员只能通过self.
访问self.
,所以这也不是问题。
如果您真的想动态创建变量,可以使用多种方法, 请参见此处 。 但是,您再次想要抽象出客户的实际数量,这就是列表的目的。
不要动态创建变量! 而是使用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
,但是这使事情变得过于复杂,因此作为一个简单函数更有意义。 而不是返回列表,而是返回Client
的字典,每个字典都以其各自的id
键。
我已经稍微简化了处理过程(尽管仍然没有错误处理),并使循环对空白行更加健壮。
我还添加了一些测试代码,以使您可以验证是否已从测试数据中正确创建了客户端,并在可以选择的情况下使类和函数import
可能。 with StringIO(data) as file:
替换with StringIO(data) as file:
用with open("Clients.txt") as file:
文件替换:而是使用真实的数据文件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.