Изучаю Python , и есть некоторые основные сомнения.
1. Я видел объявление переменной (здесь путь) как
class writer:
path = ""
иногда без явного объявления, но инициализируйте через __init__
.
def __init__(self, name):
self.name = name
Я понимаю цель __init__
, но желательно ли объявлять переменную в любых других функциях.
2. Как я могу создать переменную для хранения произвольного типа?
class writer:
path = "" # string value
customObj = ??
__name__
атрибутом имеют «имя». Не все объекты имеют__name__
атрибут, но вы все равно можете ссылаться на них. Если мы начнем называть «ссылку» «именем», мы окажем новичкам медвежью услугу в будущем.Ответы:
Хорошо, обо всем по порядку.
В Python нет таких вещей, как «объявление переменной» или «инициализация переменной».
Это просто то, что мы называем «присваиванием», но, вероятно, следует называть просто «именование».
Присваивание означает, что «это имя в левой части теперь относится к результату оценки правой части, независимо от того, на что оно ссылалось раньше (если что-либо)».
foo = 'bar' # the name 'foo' is now a name for the string 'bar' foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar', # and starts being a name for the integer 6, resulting from the multiplication
Таким образом, имена Python (возможно, более подходящий термин, чем «переменные») не имеют связанных типов; ценности делают. Вы можете повторно применить одно и то же имя ко всему, независимо от его типа, но поведение объекта по-прежнему зависит от его типа. Имя - это просто способ обозначить значение (объект). Это отвечает на ваш второй вопрос: вы не создаете переменные для хранения пользовательского типа. Вы не создаете переменные для хранения какого-либо определенного типа. Вы вообще не «создаете» переменные. Вы даете имена объектам.
Второй момент: когда дело доходит до классов, Python следует очень простому правилу, которое на самом деле гораздо более согласованно, чем то, что делают такие языки, как Java, C ++ и C #: все, что объявлено внутри
class
блока, является частью класса . Итак,def
написанные здесь функции ( ) являются методами, то есть частью объекта класса (не сохраняются для каждого экземпляра), как в Java, C ++ и C #; но другие имена здесь также являются частью класса. Опять же, имена - это просто имена, и они не имеют связанных типов, а функции также являются объектами в Python. Таким образом:class Example: data = 42 def method(self): pass
В Python классы тоже являются объектами .
Итак, теперь мы создали объект с именем
Example
, который представляет класс всех вещей, которые естьExample
. Этот объект имеет два атрибута, задаваемых пользователем (в C ++ - «члены»; в C # - «поля или свойства или методы»; в Java - «поля или методы»). Один из них названdata
, и в нем хранится целочисленное значение42
. Другой названmethod
, и он хранит объект функции. (Есть еще несколько атрибутов, которые Python добавляет автоматически.)Однако эти атрибуты по-прежнему не являются частью объекта. По сути, объект - это просто набор других имен (имен атрибутов), пока вы не перейдете к вещам, которые больше нельзя разделить. Таким образом, значения могут совместно использоваться разными экземплярами класса или даже между объектами разных классов, если вы намеренно это настроили.
Создадим экземпляр:
Теперь у нас есть отдельный объект с именем
x
, который является экземпляромExample
. На самом делеdata
иmethod
не являются частью объекта, но мы все равно можем искать их с помощьюx
некоторой магии, которую Python делает за кулисами. Вmethod
частности, когда мы смотрим вверх , мы вместо этого получим «связанный метод» (когда мы его вызываем, онx
автоматически передается в качествеself
параметра, чего не может произойти, если мы посмотримExample.method
прямо вверх ).Что происходит, когда мы пытаемся использовать
x.data
?Когда мы исследуем его, он сначала ищет объект. Если его нет в объекте, Python просматривает класс.
Однако, когда мы назначаем
x.data
, Python создаст атрибут для объекта. Он не заменит атрибут класса.Это позволяет нам выполнять инициализацию объекта . Python автоматически вызовет метод класса для
__init__
новых экземпляров при их создании, если они есть. В этом методе мы можем просто назначить атрибуты, чтобы установить начальные значения для этого атрибута для каждого объекта:class Example: name = "Ignored" def __init__(self, name): self.name = name # rest as before
Теперь мы должны указать a
name
при созданииExample
, и каждый экземпляр имеет свой собственныйname
. Python будет игнорировать атрибут классаExample.name
всякий раз, когда мы ищем.name
экземпляр экземпляра, потому что атрибут экземпляра будет найден первым.И последнее предостережение: модификация (мутация) и присвоение - разные вещи!
В Python строки неизменяемы. Их нельзя изменить. Когда вы это сделаете:
a = 'hi ' b = a a += 'mom'
Вы не меняете исходную строку «привет». В Python это невозможно. Вместо этого вы создаете новую строку
'hi mom'
и заставляетеa
перестать быть именем'hi '
, а'hi mom'
вместо этого начинаете быть именем . Мы также создалиb
имя'hi '
, и после повторного примененияa
имяb
все еще остается именем'hi '
, потому что'hi '
все еще существует и не было изменено.Но списки можно изменить:
a = [1, 2, 3] b = a a += [4]
Теперь
b
это [1, 2, 3, 4], потому что мы создалиb
имя для той же вещи, что иa
название, а затем мы изменили это. Мы не создавали новый список дляa
имени, потому что Python просто по-+=
другому относится к спискам.Это важно для объектов, потому что если бы у вас был список как атрибут класса и вы использовали экземпляр для изменения списка, то изменение было бы «видно» во всех других экземплярах. Это потому, что (а) данные на самом деле являются частью объекта класса, а не объекта-экземпляра; (b) поскольку вы изменяли список, а не выполняли простое присвоение, вы не создали новый атрибут экземпляра, скрывающий атрибут класса.
источник
Это может быть на 6 лет позже, но в Python 3.5 и выше вы объявляете тип переменной следующим образом:
или это:
variable_name # type: shinyType
Итак, в вашем случае (если у вас определен
CustomObject
класс) вы можете:См. То или это для получения дополнительной информации.
источник
В Python нет необходимости объявлять новые переменные. Если мы говорим о переменных в функциях или модулях, объявление не требуется. Просто присвоить значение имени , где вам это нужно:
mymagic = "Magic"
. Переменные в Python могут содержать значения любого типа, и вы не можете ограничить это.Однако ваш вопрос конкретно касается классов, объектов и переменных экземпляра. Идиоматический способ создания переменных экземпляра заключается в
__init__
методе и нигде больше - хотя вы можете создавать новые переменные экземпляра в других методах или даже в несвязанном коде, это просто плохая идея. Из-за этого будет сложно обдумывать или поддерживать ваш код.Так например:
class Thing(object): def __init__(self, magic): self.magic = magic
Легко. Теперь у экземпляров этого класса есть
magic
атрибут:thingo = Thing("More magic") # thingo.magic is now "More magic"
Создание переменных в пространстве имен самого класса приводит к совершенно другому поведению. Он функционально другой, и вы должны делать это только в том случае, если у вас есть для этого особая причина. Например:
class Thing(object): magic = "Magic" def __init__(self): pass
А теперь попробуйте:
thingo = Thing() Thing.magic = 1 # thingo.magic is now 1
Или:
class Thing(object): magic = ["More", "magic"] def __init__(self): pass thing1 = Thing() thing2 = Thing() thing1.magic.append("here") # thing1.magic AND thing2.magic is now ["More", "magic", "here"]
Это связано с тем, что пространство имен самого класса отличается от пространства имен объектов, созданных из него. Я предоставлю вам возможность исследовать это еще немного.
Основная идея заключается в том, что идиоматический Python должен (а) инициализировать атрибуты объекта в вашем
__init__
методе и (б) задокументировать поведение вашего класса по мере необходимости. Вам не нужно беспокоиться о полномасштабной документации уровня Sphinx для всего, что вы когда-либо писали, но по крайней мере некоторые комментарии о любых деталях, которые могут понадобиться вам или кому-то еще, чтобы это поднять.источник
Для определения объема я использую:
custom_object = None
источник
У переменных есть область видимости, поэтому да, уместно иметь переменные, специфичные для вашей функции. Вы не всегда должны четко давать их определение; обычно их можно просто использовать. Только если вы хотите сделать что-то конкретное для типа переменной, например, добавить для списка, вам нужно определить их, прежде чем вы начнете их использовать. Типичный пример этого.
list = [] for i in stuff: list.append(i)
Кстати, это не совсем хороший способ настроить список. Лучше было бы сказать:
list = [i for i in stuff] # list comprehension
... но я отвлекся.
Ваш другой вопрос. Настраиваемый объект должен быть самим классом.
class CustomObject(): # always capitalize the class name...this is not syntax, just style. pass customObj = CustomObject()
источник