【问题标题】:class variable stays empty with for loop类变量在 for 循环中保持为空
【发布时间】:2018-06-22 05:12:05
【问题描述】:

我想确保hotel_name 不存在于Hotel.hotels 列表中。 似乎当我开始喂食时,每次 for 循环都在一个空列表中查找。

请注意,如果我不使用 for 循环并且只使用

Hotel.hotels.append([number,hotel_name,city,total_number,empty_rooms])

它打印酒店列表

[[1, 'Crown Plaza', 'alex', 20, 2], [1, 'Crown Plaza', 'alex', 20, 2], [2, 'Radisson Blu', 'cairo', 24, 22], [3, 'Paradise Inn', 'dubai', 390, 200], [4, 'Four Seasons', 'alex', 1000, 400], [5, 'Address', 'dubai', 500, 200], [6, 'Fairmont', 'dubai', 1000, 100], [7, 'Rotana', 'dubai', 5000, 300]]
[Finished in 0.1s]

这是文件

class Hotel():
    """""""""
    this is hotel class file
    """
    hotels = []

    def __init__(self,number,hotel_name,city,total_number,empty_rooms):
        self.number = number
        self.hotel_name = hotel_name
        self.city = city
        self.total_number = total_number
        self.empty_rooms = empty_rooms
        for i in Hotel.hotels:
            if self.hotel_name not in i:
                Hotel.hotels.append([number,hotel_name,city,total_number,empty_rooms])
            # else:
            #     print "Hotel already exists!"

feed_dataBase_with_hotel = Hotel(1,"Crown Plaza","alex",20,2)
feed_dataBase_with_hotel = Hotel(1,"Crown Plaza","alex",20,2)# cull repeated
feed_dataBase_with_hotel = Hotel(2,"Radisson Blu","cairo",24,22)
feed_dataBase_with_hotel = Hotel(3,"Paradise Inn","dubai",390,200)
feed_dataBase_with_hotel = Hotel(4,"Four Seasons","alex",1000,400)
feed_dataBase_with_hotel = Hotel(5,"Address","dubai",500,200)
feed_dataBase_with_hotel = Hotel(6,"Fairmont","dubai",1000,100)
feed_dataBase_with_hotel = Hotel(7,"Rotana","dubai",5000,300)

print Hotel.hotels

非常感谢 Patrick 的回答 更新 如果我想从字典中构建一个列表怎么办,因为我想访问空房间并用另一个类更改它的值

class Hotel():
    """
    this is hotel class file
    """
    hotels = {}
    hotelList = []

    def __init__(self,number,hotel_name,city,total_number,empty_rooms):
        self.number = number
        self.hotel_name = hotel_name
        self.city = city
        self.total_number = total_number
        self.empty_rooms = empty_rooms

        # edited: no for needed
        if self.hotel_name in Hotel.hotels:
            print('Hotel {} Already exists!'.format(self.hotel_name))
            return # or raise ValueError & handle it

        Hotel.hotels[self.hotel_name] = self

        tempList = Hotel.hotels.items()
        for i in tempList:
            x = Hotel.hotels.items()[i][1]
            Hotel.hotelList.append(x)

更新

另一个预订类将使用我们在酒店类中使用的实例变量hotel_name

from hotel import Hotel
from customer import Customer
from notification import Notification

class Reservation():
    reservations =[]
    def reserve_room(self,hotel_name, customer_name):
        x = Hotel.hotels.values()
        for i in x:
            if Hotel.hotel_name in i:
                Reservation.reservations.append([hotel_name,customer_name])
                i[4] -=1

AttributeError: class Hotel 没有属性'hotel_name'

更新 来自Understanding getitem method 使用

def __getitem__(self, hotel_name):
          return self.hotel_name

问题已解决!

特别感谢Patrick

【问题讨论】:

  • 如果你把Hotel 实例扔掉,为什么还要创建它们?您只在feed_dataBase_with_hotel 中存储了最后一个“Hotel”。 Hotel.hotels 仅存储酒店属性的简单列表,NOT 您刚刚创建的酒店实例。因此,您可以立即创建并忘记它。如需修复,请参阅答案。
  • @PatrickArtner 感谢您的回答,您介意查看我的更新吗?
  • 我编辑了 - for 循环是多余的 - if self.hotel_name in Hotel.hotels 已经检查了 all 键。 tempList 和额外的 hotelList 也是多余的 - 而不是返回 (key,value) 元组的 dict.items() 只需使用 Hotel.hotels.values() 即可返回所有酒店实例,而无需密钥。 hth
  • 再次感谢您的精彩回答!不好意思说还有最后一个更新,请检查一下
  • 你的 i 是一个 Hotel 实例——我认为你应该在谷歌上搜索一下实例和类。您的x 是您获得的所有酒店实例,如果您是for i in x:,那么i 将依次是每个酒店实例。因此,要将酒店名称添加到预订中,请执行以下操作:Reservations.reservations.append([i.hotel_name, customer_name]) ... 请停止添加此问题,因为“价值”会随着每个问题的堆积而减少。最好提出一个新问题。

标签: python list class for-loop class-variables


【解决方案1】:

我建议改变一些东西来修复它:

  • 您正在迭代一个可能的 1000 个 Hotels 的列表以查找是否有相同的名称,如果您使用 setdict 这样做会更好,因为在这些查找中O(1)Lists 有O(n) 查找最坏情况时间,这意味着set/dict 是恒定时间,无论您有多少Hotels。列表越来越慢,您需要搜索的Hotels 越多。

  • 你用新的酒店实例覆盖相同的变量,它们自己被创建和遗忘 - 你只将它们的值存储在你的 Hotel.hotels 列表中,而不是存储构造的 Hotel 本身。 Hotel 实例的整个构造毫无意义。

建议的更改:

  • 将静态存储变成字典,让您获得快速查找的好处
  • 存储您的 Hotel-instances 而不是您创建 Hotels 时使用的值
  • 不要直接打印Hotel.hotelDict - 我介绍了一种方法,它只接受你的dicti的值并将它们排序打印 - 默认情况下我按Hotel.number排序

class Hotel():
    """""""""
    this is hotel class file
    """   
    hotelDict = {} # checking "in" for sets is much faster then list - a dict is similar
                   # fast in checking and can hold values - serves double duty here
    # sorted hotels by value, sorted by key

    @classmethod
    def getSortedHotels(cls, sortKey = lambda x:x.number):
        """Takes all values (Hotel's) from Hotel.hotelDict
        and prints them after sorting. Default sort key is Hotel.number"""
        return sorted(cls.hotelDict.values(), key=sortKey) 

    def __init__(self,number,hotel_name,city,total_number,empty_rooms):
        if hotel_name in Hotel.hotelDict:
            print("Hotel already exists: {}".format(hotel_name))
            return # or raise ValueError("Hotel already exists") and handle the error
# see https://stackoverflow.com/questions/3209233/how-to-replace-an-instance-in-init
# if you want to try to replace it using __new__() but not sure if its possible

        self.number = number
        self.hotel_name = hotel_name
        self.city = city
        self.total_number = total_number
        self.empty_rooms = empty_rooms
        Hotel.hotelDict[self.hotel_name] = self

    def __repr__(self):
        """Neater print output when printing them inside a list"""
        return "{:>3}) {} in {} has {} of wich {} are empty.".format(
        self.number,self.hotel_name,self.city,self.total_number,self.empty_rooms)
        # if you want a "simple" list-like output of your attributes:
        # comment the return above and uncomment:
        # return repr([self.number,self.hotel_name,self.city,
        #              self.total_number,self.empty_rooms])

    def __str__(self):
        """Neater print output when printing Hotel instances"""
        return self.__repr__()

测试:

feed_dataBase_with_hotel = Hotel(1,"Crown Plaza","alex",20,2)
feed_dataBase_with_hotel = Hotel(1,"Crown Plaza","alex",20,2) # cull repeated
feed_dataBase_with_hotel = Hotel(2,"Radisson Blu","cairo",24,22)
feed_dataBase_with_hotel = Hotel(3,"Paradise Inn","dubai",390,200)
feed_dataBase_with_hotel = Hotel(4,"Four Seasons","alex",1000,400)
feed_dataBase_with_hotel = Hotel(5,"Address","dubai",500,200)
feed_dataBase_with_hotel = Hotel(6,"Fairmont","dubai",1000,100)
feed_dataBase_with_hotel = Hotel(7,"Rotana","dubai",5000,300)

print Hotel.getSortedHotels() 

print Hotel(99,"NoWayInn","NoWhere",1,200)

输出:

Hotel already exists: Crown Plaza
[  1) Crown Plaza in alex has 20 of wich 2 are empty.,   
   2) Radisson Blu in cairo has 24 of wich 22 are empty.,   
   3) Paradise Inn in dubai has 390 of wich 200 are empty.,   
   4) Four Seasons in alex has 1000 of wich 400 are empty.,   
   5) Address in dubai has 500 of wich 200 are empty.,   
   6) Fairmont in dubai has 1000 of wich 100 are empty.,   
   7) Rotana in dubai has 5000 of wich 300 are empty.]

 99) NoWayInn in NoWhere has 1 of wich 200 are empty.

如果您希望您的酒店按名称排序,很简单:

print Hotel.getSortedHotels(sortKey=lambda x:x.hotel_name)

【讨论】:

  • 嗨 Patrick Artner,请您解释一下,在这里使用 classmethod 的目的是什么。 ?
  • 我要感谢您的回答,因为您回答了它并且我仍在阅读它:D
  • 试图理解自我 = Hotel.hotelDict[hotel_name] 我需要你的支持 Patrick .. 请
  • @PIG 包含所有以hotel_names 为键的实例的字典是类成员(不是实例成员,它们都是self.somethings)。如果您将某些内容标记为@classmethod 并且(通过自定义将其指定为 cls 作为第一个参数)Python 知道您将在该方法中访问类成员 - 您不需要类的实例来调用此方法,您可以简单地调用它Hotel.getSortedHotels() - 不需要 Hotel 的实例。但是,您只能访问其中的类成员(您不能使用self.hotel_name f.e.,因为您没有实例。
【解决方案2】:

看看这一行for i in Hotel.hotels:这里

for i in Hotel.hotels:
    if self.hotel_name not in i:
          Hotel.hotels.append([number,hotel_name,city,total_number,empty_rooms])

并尝试获取在哪种情况下它将填充您的数组

【讨论】:

    【解决方案3】:

    问题是您在迭代一个空的“酒店”列表时 .append 。 首先在 for 循环中检查现有的 hotel_name,然后再追加。

    for hotel in self.hotels:
        if self.hotel_name == hotel[1]:  # hotel_name is at index 1
            print('Already exists!')
            return  # return before appending
    #now append
    self.hotels.append([number,hotel_name,city,total_number,empty_rooms])
    

    如果你不想退货,试试这个

    for hotel in self.hotels:
        if self.hotel_name == hotel[1]:  # hotel_name is at index 1
            print('Already exists!')
            break
    else:  # break did not happen
        self.hotels.append([number,hotel_name,city,total_number,empty_rooms])
    

    【讨论】:

    • 如果我想在这次退货后继续喂食,我该怎么做?
    • 休息时会添加重复的酒店
    • 如果发生中断,则不会触发 else 块。代码中必须有另一个错误。也许在课堂上进行过滤确实是这样,但你还是要为数据库提供信息?尝试实例化所有酒店,然后迭代调用“feed_dataBase_with_hotel”的 Hotel.hotels。为什么你把这个名字当作一个变量而不是一个函数来赋值?
    • @ahmedyounes 其他想法:似乎没有必要使用类作为简单的过滤器。 dict 使用 hotel_names 作为键或保留一个 set 使用过的名称可能是更好的方法。如需更紧凑的代码,您可以查看filter 函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-20
    • 2014-10-17
    • 1970-01-01
    • 2020-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多