#python #operator-overloading
#python #оператор-перегрузка
Вопрос:
Как вы можете эмулировать перегрузку оператора присваивания в Python? Например…
class Example(object):
name = String()
age = Integer()
def __init__(self,myname,myage):
self.name.value = myname
self.age.value = myage
Вместо того, чтобы выполнять self.name.value = name, как вы можете эмулировать перегрузку оператора присваивания, чтобы myname присваивалось self.name.value при выполнении self.name = мое имя?
Комментарии:
1. В итоге я создал метакласс для регистрации типизированных атрибутов (которые являются всеми подклассами
Property
класса). Затем я перегрузил__setattr__
метод в классеExample
(Model
) для проверки типов атрибутов, зарегистрированных метаклассом. Смотрите github.com/espeed/bulbs/blob/master/bulbs/model.py2. Используете ли вы
traits
?3. Нет, я создал свой собственный
Property
класс github.com/espeed/bulbs/blob/master/bulbs/property.py , который использует метакласс модели. Смотрите документацию по API модели Bulbs bulbflow.com/docs/api/bulbs/model4. Ознакомьтесь с
traits
библиотекой Enthought. (В нем есть что-то подобное, с большей поддержкой других материалов). Кроме того, вам нужны дескрипторы . Там есть пример примерно того же.
Ответ №1:
В этом очень особом случае, при назначении атрибута, вы можете использовать descriptor
. На самом деле, я подозреваю, что в примере, который вы используете, Integer
и String
на самом деле являются дескрипторами.
Помимо использования готовых дескрипторов, самый простой способ использовать дескрипторы с property()
. вот краткий пример:
>>> class Foo(object):
@property
def bar(self):
print 'bar'
return 'bar'
@bar.setter
def bar(self, value):
print 'bar =', value
>>> afoo = Foo()
>>> afoo.bar
bar
'bar'
>>> afoo.bar = 'baz'
bar = baz
>>>
Комментарии:
1. Да, это может сработать. Я создал класс String() с __get__(), __set__() и методом to_db(); однако, когда я выполняю name = String(), я не могу выполнить self.name.to_db(), потому что он вызывает to_db() для значения, возвращаемого __get__(), а не для объекта «name». Один из способов справиться с этим — не вызывать self.name.to_db() напрямую, а вместо этого установить флаг в экземпляре и создать условие в __get__(), чтобы проверить его и вызвать to_db(), если это правда, но это кажется запутанным. Есть ли способ лучше?
2. Если вы хотите иметь возможность выполнять
self.attr1.attr2
, вам, вероятно, не нужен дескриптор дляattr1
. Во-первых, у вас обычно нет одного дескриптора на экземпляр, у вас есть по одному на класс, поэтому вам придется столкнуться с большими трудностями при получении информации для каждого экземпляра. Дескрипторы в основном служат для скрытия деталей реализации, таких как сохранение базы данных. Вместо этого вы должны реализовать полную функциональность в терминах имен специальных методов дескриптора и, возможно, метакласса в родительском.
Ответ №2:
Вы не можете перегрузить оператор присваивания в python, однако с помощью некоторой хитроумной перегрузки магических методов вы можете получить A <<= B C, перегрузив магический метод rshift, подробное руководство по магическим методам pythons смотрите здесь.
Ответ №3:
Вы не можете перегружать присваивание. Это не оператор. Здесь было бы лучше просто создать значение в конструкторе объекта.
class Example(object):
def __init__(self,myname, myage):
self.name = String(myname)
self.age = Integer(myage)
Однако в этом случае я не понимаю, почему вы не можете просто использовать встроенные str
и int
.
Ответ №4:
В итоге я создал метакласс модели под названием ModelMeta, который регистрирует типизированные атрибуты.
Смотрите http://github.com/espeed/bulbs/blob/master/bulbs/model.py
В этом случае типизированными атрибутами являются «свойства» графической базы данных, которые являются всеми подклассами класса Property.
Смотрите https://github.com/espeed/bulbs/blob/master/bulbs/property.py
Вот пример объявления модели:
# people.py
from bulbs.model import Node, Relationship
from bulbs.property import String, Integer, DateTime
from bulbs.utils import current_datetime
class Person(Node):
element_type = "person"
name = String(nullable=False)
age = Integer()
class Knows(Relationship):
label = "knows"
created = DateTime(default=current_datetime, nullable=False)
Пример использования:
>>> from people import Person
>>> from bulbs.neo4jserver import Graph
>>> g = Graph()
# Add a "people" proxy to the Graph object for the Person model:
>>> g.add_proxy("people", Person)
# Use it to create a Person node, which also saves it in the database:
>>> james = g.people.create(name="James")
>>> james.eid
3
>>> james.name
'James'
# Get the node (again) from the database by its element ID:
>>> james = g.people.get(james.eid)
# Update the node and save it in the database:
>>> james.age = 34
>>> james.save()
# Lookup people using the Person model's primary index:
>>> nodes = g.people.index.lookup(name="James")
Смотрите…
- API модели Bulbs:http://bulbflow.com/docs/api/bulbs/model /
- Быстрый запуск модели Bulbs:http://bulbflow.com/quickstart/#models