我有一个带有一系列客户端的文本文件。 每行都有一个不同的客户端。 每个客户端都有一个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 中使用它们,那么在read()中使用“用户名”和“密码”变量时是否会有问题?
谢谢
答案 0 :(得分:2)
在循环中,您正在使用break
。不要那样做,您要使用的是continue
,它会跳过而不是让您退出迭代。
您仅在密码上使用strip('\n')
。您应该对所有物品都这样做(以确保它们都统一)。但是,仅在密码情况下才使用strip('\n')
是正确的,因为它是唯一具有\n
的密码。请勿在{{1}}中添加参数,它会处理所有空格,制表符以及其他strip()
,\n
等。
您应该将类的\r
参数看作是驻留在其中的self
。这是“环境” ,您基本上可以在类中的任何地方进行访问。而且,如果您在box
中创建某些内容,例如self
,则它将与名为self.client
的单个变量不同。您可能想在这里做的就是将刚刚阅读的客户列表分配给client
,例如self
。
您要做的不是创建与用户一样多的变量。但是您的哲学正确,您想将它们存储在一个地方。那就是你所做的。现在,您的程序的要点对我们还是很模糊。但是您可能想要做的是:
拥有一个数据库,在其中您知道如何订购商品。您知道,在users_list的每个元素中,都有第一项是self.client_list = self.read()
,第二项是id
,第三项是name
。
根据此数据库进行操作。
答案 1 :(得分:1)
您已经拥有的客户列表有什么问题?您可以使用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
函数是外部函数,并且只使用了__init__
类的Client
,那么有人可以在某个地方 add 一个新的自由函数。这是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.
访问班级的成员,所以这也不是问题。
如果您真的想动态创建变量,可以使用see here的方法。但是,您还是想抽象出实际的客户数量,这就是列表的目的。
答案 2 :(得分:1)
不要动态创建变量!而是使用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 open("Clients.txt") as file:
可以使用真实的数据文件。