2017-01-28 13 views
0

Я учусь Kivy, и цель, если этот кусок кода кэшировать виджет, но у меня возникают проблемы с пониманием того, что происходит с ним:Почему эта переменная класса None, даже если она была инициализирована?

class WeatherRoot(BoxLayout): 
    current_weather = ObjectProperty() 

    def show_current_weather(self, location=None): 
     self.clear_widgets() 

     print(WeatherRoot.current_weather) 
     print(self.current_weather) 

     if location is None and self.current_weather is None: 
      location = 'New York (US)' 

     if location is not None: 
      self.current_weather = Factory.CurrentWeather() 
      self.current_weather.location = location 
     self.add_widget(self.current_weather) 

Проблема заключается в том, что current_weather, насколько Я знаю, что это переменная класса, определяется как ObjectProperty, и поскольку у меня нет переменной экземпляра (я так думаю), которая переопределяет эту переменную, когда я ссылаюсь self.current_weather Я имею в виду переменную класса, поэтому я считаю, что self.current_weather - это то же самое, что и WeatherRoot.current_weather, но с тех пор, когда я напечатал эти переменные, я ожидал, что оба экземпляра будут ObjectProperty, и я получил:

<ObjectProperty name=current_weather> 
None 

Я считаю, что эта переменная никогда не будет None, потому что это переменная класса, так что всегда ObjectProperty, но мне кажется, что можно быть None, и я не понимаю, почему.

Это графический интерфейс этого приложения:

enter image description here

enter image description here

Это мой Kivy файл:

WeatherRoot: 
<WeatherRoot>: 
    AddLocationForm 

<LocationButton>: 
    on_press: app.root.show_current_weather(self.text) 

<AddLocationForm>: 
    orientation: 'vertical' 
    search_input: search_box 
    search_results: search_results_list 
    BoxLayout: 
     height: '40dp' 
     size_hint_y: None 
     TextInput: 
      id: search_box 
      size_hint_x: 50 
      focus: True 
      multiline: False 
      on_text_validate: root.search_location() 
     Button: 
      text: 'Search' 
      size_hint_x: 25 
      on_press: root.search_location() 
     Button: 
      text: 'Current Search' 
      size_hint_x: 25 
    ListView: 
     id: search_results_list 
     adapter: 
      ListAdapter(data=[], cls=main.LocationButton) 
    Button: 
     height: '40dp' 
     size_hint_y: None 
     text: 'Cancel' 
     on_press: app.root.show_current_weather(None) 

Так что, когда я нажимаю кнопку отмены и нет ранее было обнаружено местоположение, значение по умолчанию жестко запрограммировано, как это видно на 'New York (US). Когда я раньше искал местоположение и нажимаю кнопку «Отмена», это местоположение отображается.

Может ли кто-нибудь объяснить мне, что происходит с этой переменной current_weather? Я думал, что эта переменная класса не нужна, но когда я удалил ее, мое приложение разбилось.

В случае, если вам нужно, это весь код у меня есть:

import json 

from kivy.app import App 
from kivy.network.urlrequest import UrlRequest 
from kivy.properties import ObjectProperty 
from kivy.uix.boxlayout import BoxLayout 
from kivy.uix.listview import ListItemButton 
from kivy.factory import Factory 

class WeatherRoot(BoxLayout): 
    current_weather = ObjectProperty() 

    def show_current_weather(self, location=None): 
     self.clear_widgets() 

     print(WeatherRoot.current_weather) 
     print(self.current_weather) 

     if location is None and self.current_weather is None: 
      location = 'New York (US)' 

     if location is not None: 
      self.current_weather = Factory.CurrentWeather() 
      self.current_weather.location = location 
     self.add_widget(self.current_weather) 

    def show_add_location_form(self): 
     self.clear_widgets() 
     self.add_widget(AddLocationForm()) 


class LocationButton(ListItemButton): 
    pass 


class AddLocationForm(BoxLayout): 
    search_input = ObjectProperty() 
    search_results = ObjectProperty() 

    def search_location(self): 
     search_template = 'http://api.openweathermap.org/' \ 
          'data/2.5/find?q={}&type=like&APPID=' \ 
          '090428d02304be901047796d430986e3' 
     search_url = search_template.format(self.search_input.text) 
     print(search_url) 
     request = UrlRequest(search_url, self.found_location) 

    def found_location(self, request, data): 
     data = json.loads(data.decode()) if not isinstance(data, dict) else data 
     cities = ['{} ({})'.format(d['name'], d['sys']['country']) 
        for d in data['list']] 
     # self.search_results.item_strings = cities 
     self.search_results.adapter.data.clear() 
     self.search_results.adapter.data.extend(cities) 
     self.search_results._trigger_reset_populate() 


class WeatherApp(App): 
    pass 


WeatherApp().run() 

ответ

2

Свойства descriptors. Хотя они определены на уровне класса, они имеют поведение на уровне экземпляра, и в первом приближении будут вести себя как переменная экземпляра.

+0

, когда вы говорите, что __Properties являются дескрипторами__, вы заявляете, что свойства Kivy определены как дескрипторы? Или вы имеете в виду, что это свойства Python, то есть метод, к которому можно получить доступ, как если бы это был атрибут? – lmiguelvargasf

+1

Свойства Kivy являются дескрипторами в том смысле, что они реализуют протокол дескриптора, как в связанной документации. Они похожи на обычные свойства python в том, как они себя ведут, но их реализация отличается (и включает в себя дополнительное поведение). – inclement