I'm working under python pyramid, with Python3.
I have a model that looks like this:
class OneTimeCode(Base):
__tablename__ = 'otc_one_time_codes'
otc_one_time_code_id = Column(Integer, primary_key=True)
otc_one_time_code = Column(String(32))
otc_usr_user_id = Column(Integer, ForeignKey('usr_users.usr_user_id'), nullable=True)
otc_expire_time = Column(DateTime)
def __init__(self, otc_usr_user_id, otc_expire_time=None):
self.otc_usr_user_id = otc_usr_user_id
if otc_expire_time is None:
self.otc_expire_time = (datetime.now() + timedelta(6*365/12)).isoformat()
else:
self.otc_expire_time = otc_expire_time
@classmethod
def get_code(self, hlength=6):
seed = datetime.now() + timedelta(random.randrange(1,10000))
tmp_hash = hashlib.md5(seed.strftime("%Y-%m-%d %H:%M:%S.%F").encode('utf-8')).hexdigest()
if hlength == 32:
self.otc_one_time_code = tmp_hash
else:
self.otc_one_time_code = tmp_hash[0 : hlength]
print(self.otc_one_time_code)
The problem is, when I instantiate one of these objects and then explicitly call get_code, the print line at the end prints to the screen the code successfully.
However, in my view, if I explicitly try to print that property, it's 'None'
Here's what my view code looks like:
otc = OneTimeCode(
otc_usr_user_id = user.usr_user_id
)
otc.get_code()
pprint.pprint(vars(otc))
session.add(otc)
And the console output looks like this:
0d097c
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x50877d0>, 'otc_expire_time': '2015-02-13T10:56:14.244447', 'otc_usr_user_id': 1} 2014-08-14 22:56:14,245
INFO [sqlalchemy.engine.base.Engine][Dummy-2] INSERT INTO otc_one_time_codes (otc_one_time_code, otc_usr_user_id, otc_expire_time) VALUES (%(otc_one_time_code)s, %(otc_usr_user_id)s, %(otc_expire_time)s) RETURNING otc_one_time_codes.otc_one_time_code_id 2014-08-14 22:56:14,245
INFO [sqlalchemy.engine.base.Engine][Dummy-2] {'otc_one_time_code': None, 'otc_expire_time': '2015-02-13T10:56:14.244447', 'otc_usr_user_id': 1} 2014-08-14 22:56:14,247
INFO [sqlalchemy.engine.base.Engine][Dummy-2] COMMIT
You can see the value inside the model: 0d097c, and also the pprint object, where it doesn't look like the property exists.
Why can't I get access to this property?
Looks like you should be using a @property
instead of a OTC
, however it also seems like this may be something you DON'T want to calculate each time!
# for all the docstrings, let multi = Multi(2)
class Multi(object):
def __init__(self, attribute):
"""When instantiated, set self.attribute to attribute"""
self.attribute = attribute
@property
def attribute_times_ten(self):
"""accessed via multi.attribute_times_ten
and will return 20. Use properties to signify
a variable that requires some work done to it
that needs to calculated each time it's called."""
return attribute_times_ten
@classmethod
def times_ten(cls, num):
"""Not the best example, but a @classmethod will
give the class as its first argument, NOT the
instance. This is useful in lots of constructor
settings, e.g. CreateClass.fromstring("attributes")"""
return num * 5
def generate_number(self, multiplier):
"""This is just a normal method. This is what I think
you want, tbh, and you should probably call it in your
__init__ method since you NEED this to run in your OTC
for it to work as intended. Methods (like properties)
are automagically passed the instance as the first
argument, so we can CHANGE self.attribute with that."""
self.attribute = self.attribute * multiplier
Docstrings should be self descriptive, but:
multi = Multi(2)
multi.attribute_times_ten # returns 20
Multi.times_ten(8) # returns 80, note the capital M!
multi.generate_number(3) # self.attribute is now 6
multi.attribute_times_ten # returns 60
A real-world case where you might need all of the above:
class _Tile(object):
def __init__(self, x, y):
"""A naive implementation of Tile that doesn't care
what its side length is and doesn't have any properties
to hide its attributes"""
self.x = x
self.y = y
@classmethod
def tiles_to_pixels(cls, tile):
return cls(tile._x * tile.side_length, tile._y * tile.side_length)
@classmethod
def tiles_to_tiles(cls, tile):
return cls(tile._x, tile._y)
class Tile(object):
def __init__(self, x, y, side_length):
"""A tile object in a map"""
self._x = x # x-coord in tiles
self._y = y # y-coord in tiles
self.side_length = side_length # pixels per tile
@property
def in_pixels(self):
"""self.in_pixels returns an object whose .x and .y
correspond to the x and y position IN PIXELS of the
top-left corner of the tile."""
_tile = _Tile.tiles_to_pixels(self)
return _tile
@property
def in_tiles(self):
"""self.in_tiles returns an object whose .x and .y
correspond to the x and y position IN TILES of the
top-left corner of the tile."""
_tile = _Tile.tiles_to_tiles(self)
return _tile
def change_side_length(self, new_length):
"""Use to change the side length. This can break
your whole map since it's naive, so be careful."""
self.side_length = new_length
my_tile = Tile(0,0,32) # 32 pixel tile starting at (0,0)
my_tile.x # NameError, since it's called my_tile._x
my_tile.in_tiles.x # 0
my_tile.in_pixels.y # 0
other_tile = Tile(4,7,32) # 32 pixel tile starting at (4,7)
other_tile.y # NameError, see above
other_tile.in_tiles.y # 7
other_tile.in_pixels.x # 128
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.