Можете ли вы попробовать
// Create a reference to the file you want to download
let starsRef = storageRef.child("images/stars.jpg")
// Fetch the download URL
starsRef.downloadURL { url, error in
if let error = error {
// Handle any errors
} else {
// Get the download URL for 'images/stars.jpg'
}
}
Если вы попытаетесь запустить этот код, вы получите:
NameError: name 'Position' is not defined
Это связано с тем, что Position
необходимо определить, прежде чем вы сможете использовать его в аннотации. «Благословенный путь» и торговля; заключается в использовании строки, если вы используете Python & lt; 3.7 или импортируете модуль аннотаций из future
, если вы уже используете Python 3.7 (запущен в июне 2018 года), но я также рассмотрю обходные пути, предложенные для подобных вопросов.
from __future__ import annotations
Python 3.7 вводит PEP 563: отложенная оценка аннотаций . Модуль, который использует будущий оператор from __future__ import annotations
, автоматически сохранит аннотации в виде строк:
from __future__ import annotations
class Position:
def __add__(self, other: Position) -> Position:
...
В Python 4.0 это станет стандартным. Поскольку Python по-прежнему является динамически типизированным языком, поэтому во время выполнения проверка типа не выполняется, написание аннотаций не должно влиять на производительность, верно? Неправильно! До того, как в python 3.7 был выбран модуль ввода , один из самых медленных модулей python в ядре , поэтому, если вы import typing
, вы увидите до 7-кратного увеличения производительности при обновлении к 3.7.
Согласно PEP 484 , вы должны использовать строку вместо самого класса:
class Position:
...
def __add__(self, other: 'Position') -> 'Position':
...
Если вы используете фреймворк Django, это может быть знакомо, поскольку модели Django также используют строки для прямых ссылок (определения внешних ключей, в которых внешняя модель self
или еще не объявлена). Это должно работать с Pycharm и другими инструментами.
Соответствующие части PEP 484 и PEP 563 , чтобы сэкономить вы путешествуете:
Прямые ссылки
Если подсказка типа содержит имена, которые еще не определены, это определение может быть выражено как строковый литерал, который будет разрешен позже .
Ситуация, в которой это происходит, обычно является определением класса контейнера, где определяемый класс встречается в сигнатуре некоторых из методов. Например, следующий код (начало простой реализации двоичного дерева) не работает:
blockquote>class Tree: def __init__(self, left: Tree, right: Tree): self.left = left self.right = right
Чтобы решить эту проблему, напишем:
blockquote>class Tree: def __init__(self, left: 'Tree', right: 'Tree'): self.left = left self.right = right
Строковый литерал должен содержать допустимое выражение Python (т. е. компиляция (lit, '', 'eval') должна быть допустимым объектом кода), и она должна оцениваться без ошибок после того, как модуль была полностью загружена. Локальное и глобальное пространство имен, в котором он оценивается, должны быть теми же пространствами имен, в которых будут оцениваться аргументы по умолчанию для одной и той же функции.
blockquote>и PEP 563:
В Python 4.0 аннотации функций и переменных больше не будут оцениваться во время определения. Вместо этого строковая форма будет сохранена в соответствующем словаре
__annotations__
. Тестеры статического типа не будут видеть различий в поведении, тогда как инструменты, использующие аннотации во время выполнения, должны будут выполнить отложенную оценку....
Функцию, описанную выше, можно включить, начиная с Python 3.7, используя следующий специальный импорт:
blockquote>from __future__ import annotations
Вещи, которые могут возникнуть у вас, вместо этого
A. Определите манекен
Position
Перед определением класса поместите фиктивное определение:
class Position(object): pass class Position(object): ...
Это избавится от
NameError
и даже может выглядеть нормально:>>> Position.__add__.__annotations__ {'other': __main__.Position, 'return': __main__.Position}
Но это?
>>> for k, v in Position.__add__.__annotations__.items(): ... print(k, 'is Position:', v is Position) return is Position: False other is Position: False
B. Monkey-patch для добавления аннотаций:
Возможно, вы захотите попробовать магию программирования метафайлов Python и написать декоратор, чтобы обезопасить определение класса, чтобы добавить аннотации:
class Position: ... def __add__(self, other): return self.__class__(self.x + other.x, self.y + other.y)
Декоратор должен отвечать за эквивалент этого:
Position.__add__.__annotations__['return'] = Position Position.__add__.__annotations__['other'] = Position
По крайней мере, кажется правильным:
>>> for k, v in Position.__add__.__annotations__.items(): ... print(k, 'is Position:', v is Position) return is Position: True other is Position: True
Вероятно, слишком много проблем.
Заключение
Если вы используете 3.6 или ниже, используйте строковый литерал, содержащий имя класса, в 3.7 используйте
from __future__ import annotations
, и он будет работать.
Название «Позиция» не может быть доступно в то время, когда само тело класса анализируется. Я не знаю, как вы используете объявления типа, но PEP 484 Python - это то, что большинство режимов должно использовать, если использовать эти подсказки для печати, скажем, что вы можете просто поместить имя в виде строки в этот момент:
def __add__(self, other: 'Position') -> 'Position':
return Position(self.x + other.x, self.y + other.y)
Проверить https://www.python.org/dev/peps/pep-0484/#forward-references - инструменты, соответствующие этому, будут знать, чтобы развернуть имя класса оттуда и (всегда важно иметь в виду, что сам язык Python ничего не делает из этих аннотаций - они обычно предназначены для анализа статического кода или могут иметь библиотеку / фреймворк для проверки типов во время выполнения - но вы должны явно установить это)
Указание типа как строки в порядке, но всегда немного меня решает, что мы в основном обходим парсер. Поэтому вам лучше не пропустить ни одну из этих литералов:
def __add__(self, other: 'Position') -> 'Position':
return Position(self.x + other.x, self.y + other.y)
Небольшое отклонение заключается в использовании связанного типаvar, по крайней мере, тогда вы должны написать строку только один раз при объявлении typevar:
from typing import TypeVar
T = TypeVar('T', bound='Position')
class Position:
def __init__(self, x: int, y: int):
self.x = x
self.y = y
def __add__(self, other: T) -> T:
return Position(self.x + other.x, self.y + other.y)